Actual source code: posindep.c
1: #define PETSCTS_DLL
3: /*
4: Code for Timestepping with implicit backwards Euler.
5: */
6: #include private/tsimpl.h
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 */
13: /* information used for Pseudo-timestepping */
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;
20: PetscReal initial_fnorm,fnorm; /* original and current norm of F(u) */
21: PetscReal fnorm_previous;
23: PetscReal dt_increment; /* scaling that dt is incremented each time-step */
24: PetscTruth increment_dt_from_initial_dt;
25: } TS_Pseudo;
27: /* ------------------------------------------------------------------------------*/
31: /*@
32: TSPseudoComputeTimeStep - Computes the next timestep for a currently running
33: pseudo-timestepping process.
35: Collective on TS
37: Input Parameter:
38: . ts - timestep context
40: Output Parameter:
41: . dt - newly computed timestep
43: Level: advanced
45: Notes:
46: The routine to be called here to compute the timestep should be
47: set by calling TSPseudoSetTimeStep().
49: .keywords: timestep, pseudo, compute
51: .seealso: TSPseudoDefaultTimeStep(), TSPseudoSetTimeStep()
52: @*/
53: PetscErrorCode TSPseudoComputeTimeStep(TS ts,PetscReal *dt)
54: {
55: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
59: PetscLogEventBegin(TS_PseudoComputeTimeStep,ts,0,0,0);
60: (*pseudo->dt)(ts,dt,pseudo->dtctx);
61: PetscLogEventEnd(TS_PseudoComputeTimeStep,ts,0,0,0);
62: return(0);
63: }
66: /* ------------------------------------------------------------------------------*/
69: /*@C
70: TSPseudoDefaultVerifyTimeStep - Default code to verify the quality of the last timestep.
72: Collective on TS
74: Input Parameters:
75: + ts - the timestep context
76: . dtctx - unused timestep context
77: - update - latest solution vector
79: Output Parameters:
80: + newdt - the timestep to use for the next step
81: - flag - flag indicating whether the last time step was acceptable
83: Level: advanced
85: Note:
86: This routine always returns a flag of 1, indicating an acceptable
87: timestep.
89: .keywords: timestep, pseudo, default, verify
91: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoVerifyTimeStep()
92: @*/
93: PetscErrorCode TSPseudoDefaultVerifyTimeStep(TS ts,Vec update,void *dtctx,PetscReal *newdt,PetscTruth *flag)
94: {
96: *flag = PETSC_TRUE;
97: return(0);
98: }
103: /*@
104: TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.
106: Collective on TS
108: Input Parameters:
109: + ts - timestep context
110: - update - latest solution vector
112: Output Parameters:
113: + dt - newly computed timestep (if it had to shrink)
114: - flag - indicates if current timestep was ok
116: Level: advanced
118: Notes:
119: The routine to be called here to compute the timestep should be
120: set by calling TSPseudoSetVerifyTimeStep().
122: .keywords: timestep, pseudo, verify
124: .seealso: TSPseudoSetVerifyTimeStep(), TSPseudoDefaultVerifyTimeStep()
125: @*/
126: PetscErrorCode TSPseudoVerifyTimeStep(TS ts,Vec update,PetscReal *dt,PetscTruth *flag)
127: {
128: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
132: if (!pseudo->verify) {*flag = PETSC_TRUE; return(0);}
134: (*pseudo->verify)(ts,update,pseudo->verifyctx,dt,flag);
136: return(0);
137: }
139: /* --------------------------------------------------------------------------------*/
143: static PetscErrorCode TSStep_Pseudo(TS ts,PetscInt *steps,PetscReal *ptime)
144: {
145: Vec sol = ts->vec_sol;
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:
153: *steps = -ts->steps;
155: VecCopy(sol,pseudo->update);
156: for (i=0; i<max_steps && ts->ptime < ts->max_time; i++) {
157: TSPseudoComputeTimeStep(ts,&ts->time_step);
158: TSMonitor(ts,ts->steps,ts->ptime,sol);
159: current_time_step = ts->time_step;
160: TSPreStep(ts);
161: while (PETSC_TRUE) {
162: ts->ptime += current_time_step;
163: SNESSolve(ts->snes,PETSC_NULL,pseudo->update);
164: SNESGetLinearSolveIterations(ts->snes,&lits);
165: SNESGetIterationNumber(ts->snes,&its);
166: ts->nonlinear_its += its; ts->linear_its += lits;
167: TSPseudoVerifyTimeStep(ts,pseudo->update,&ts->time_step,&ok);
168: if (ok) break;
169: ts->ptime -= current_time_step;
170: current_time_step = ts->time_step;
171: }
172: VecCopy(pseudo->update,sol);
173: ts->steps++;
174: TSPostStep(ts);
175: }
176: TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
177: VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
178: TSMonitor(ts,ts->steps,ts->ptime,sol);
180: *steps += ts->steps;
181: *ptime = ts->ptime;
182: return(0);
183: }
185: /*------------------------------------------------------------*/
188: static PetscErrorCode TSDestroy_Pseudo(TS ts)
189: {
190: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
194: if (pseudo->update) {VecDestroy(pseudo->update);}
195: if (pseudo->func) {VecDestroy(pseudo->func);}
196: if (pseudo->xdot) {VecDestroy(pseudo->xdot);}
197: PetscFree(pseudo);
198: return(0);
199: }
202: /*------------------------------------------------------------*/
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;
214: PetscInt i,n;
217: VecGetArray(ts->vec_sol,&xn);
218: VecGetArray(X,&xnp1);
219: VecGetArray(pseudo->xdot,&xdot);
220: VecGetLocalSize(X,&n);
221: for (i=0; i<n; i++) {
222: xdot[i] = mdt*(xnp1[i] - xn[i]);
223: }
224: VecRestoreArray(ts->vec_sol,&xn);
225: VecRestoreArray(X,&xnp1);
226: VecRestoreArray(pseudo->xdot,&xdot);
227: *Xdot = pseudo->xdot;
228: return(0);
229: }
233: /*
234: The transient residual is
236: F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
238: or for ODE,
240: (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
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 TSPseudoFunction(SNES snes,Vec X,Vec Y,void *ctx)
251: {
252: TS ts = (TS)ctx;
253: Vec Xdot;
257: TSPseudoGetXdot(ts,X,&Xdot);
258: TSComputeIFunction(ts,ts->ptime,X,Xdot,Y);
259: return(0);
260: }
264: /*
265: This constructs the Jacobian needed for SNES. For DAE, this is
267: dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
269: and for ODE:
271: J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs.
272: */
273: static PetscErrorCode TSPseudoJacobian(SNES snes,Vec X,Mat *AA,Mat *BB,MatStructure *str,void *ctx)
274: {
275: TS ts = (TS)ctx;
276: Vec Xdot;
280: TSPseudoGetXdot(ts,X,&Xdot);
281: TSComputeIJacobian(ts,ts->ptime,X,Xdot,1./ts->time_step,AA,BB,str);
282: return(0);
283: }
288: static PetscErrorCode TSSetUp_Pseudo(TS ts)
289: {
290: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
294: VecDuplicate(ts->vec_sol,&pseudo->update);
295: VecDuplicate(ts->vec_sol,&pseudo->func);
296: VecDuplicate(ts->vec_sol,&pseudo->xdot);
297: SNESSetFunction(ts->snes,pseudo->func,TSPseudoFunction,ts);
298: SNESSetJacobian(ts->snes,ts->Arhs,ts->B,TSPseudoJacobian,ts);
299: return(0);
300: }
301: /*------------------------------------------------------------*/
305: PetscErrorCode TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void *ctx)
306: {
307: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
308: PetscErrorCode ierr;
309: PetscViewerASCIIMonitor viewer = (PetscViewerASCIIMonitor)ctx;
312: if (!ctx) {
313: PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);
314: }
315: PetscViewerASCIIMonitorPrintf(viewer,"TS %D dt %G time %G fnorm %G\n",step,ts->time_step,ptime,pseudo->fnorm);
316: if (!ctx) {
317: PetscViewerASCIIMonitorDestroy(viewer);
318: }
319: return(0);
320: }
324: static PetscErrorCode TSSetFromOptions_Pseudo(TS ts)
325: {
326: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
327: PetscErrorCode ierr;
328: PetscTruth flg = PETSC_FALSE;
329: PetscViewerASCIIMonitor viewer;
332: PetscOptionsHead("Pseudo-timestepping options");
333: PetscOptionsTruth("-ts_monitor","Monitor convergence","TSPseudoMonitorDefault",flg,&flg,PETSC_NULL);
334: if (flg) {
335: PetscViewerASCIIMonitorCreate(((PetscObject)ts)->comm,"stdout",0,&viewer);
336: TSMonitorSet(ts,TSPseudoMonitorDefault,viewer,(PetscErrorCode (*)(void*))PetscViewerASCIIMonitorDestroy);
337: }
338: flg = PETSC_FALSE;
339: PetscOptionsTruth("-ts_pseudo_increment_dt_from_initial_dt","Increase dt as a ratio from original dt","TSPseudoIncrementDtFromInitialDt",flg,&flg,PETSC_NULL);
340: if (flg) {
341: TSPseudoIncrementDtFromInitialDt(ts);
342: }
343: PetscOptionsReal("-ts_pseudo_increment","Ratio to increase dt","TSPseudoSetTimeStepIncrement",pseudo->dt_increment,&pseudo->dt_increment,0);
344: PetscOptionsTail();
345: return(0);
346: }
350: static PetscErrorCode TSView_Pseudo(TS ts,PetscViewer viewer)
351: {
353: return(0);
354: }
356: /* ----------------------------------------------------------------------------- */
359: /*@C
360: TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
361: last timestep.
363: Collective on TS
365: Input Parameters:
366: + ts - timestep context
367: . dt - user-defined function to verify timestep
368: - ctx - [optional] user-defined context for private data
369: for the timestep verification routine (may be PETSC_NULL)
371: Level: advanced
373: Calling sequence of func:
374: . func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscTruth *flag);
376: . update - latest solution vector
377: . ctx - [optional] timestep context
378: . newdt - the timestep to use for the next step
379: . flag - flag indicating whether the last time step was acceptable
381: Notes:
382: The routine set here will be called by TSPseudoVerifyTimeStep()
383: during the timestepping process.
385: .keywords: timestep, pseudo, set, verify
387: .seealso: TSPseudoDefaultVerifyTimeStep(), TSPseudoVerifyTimeStep()
388: @*/
389: PetscErrorCode TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (*dt)(TS,Vec,void*,PetscReal*,PetscTruth*),void* ctx)
390: {
391: PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,Vec,void*,PetscReal *,PetscTruth *),void *);
396: PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",(void (**)(void))&f);
397: if (f) {
398: (*f)(ts,dt,ctx);
399: }
400: return(0);
401: }
405: /*@
406: TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
407: dt when using the TSPseudoDefaultTimeStep() routine.
409: Collective on TS
411: Input Parameters:
412: + ts - the timestep context
413: - inc - the scaling factor >= 1.0
415: Options Database Key:
416: $ -ts_pseudo_increment <increment>
418: Level: advanced
420: .keywords: timestep, pseudo, set, increment
422: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
423: @*/
424: PetscErrorCode TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)
425: {
426: PetscErrorCode ierr,(*f)(TS,PetscReal);
431: PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",(void (**)(void))&f);
432: if (f) {
433: (*f)(ts,inc);
434: }
435: return(0);
436: }
440: /*@
441: TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
442: is computed via the formula
443: $ dt = initial_dt*initial_fnorm/current_fnorm
444: rather than the default update,
445: $ dt = current_dt*previous_fnorm/current_fnorm.
447: Collective on TS
449: Input Parameter:
450: . ts - the timestep context
452: Options Database Key:
453: $ -ts_pseudo_increment_dt_from_initial_dt
455: Level: advanced
457: .keywords: timestep, pseudo, set, increment
459: .seealso: TSPseudoSetTimeStep(), TSPseudoDefaultTimeStep()
460: @*/
461: PetscErrorCode TSPseudoIncrementDtFromInitialDt(TS ts)
462: {
463: PetscErrorCode ierr,(*f)(TS);
468: PetscObjectQueryFunction((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",(void (**)(void))&f);
469: if (f) {
470: (*f)(ts);
471: }
472: return(0);
473: }
478: /*@C
479: TSPseudoSetTimeStep - Sets the user-defined routine to be
480: called at each pseudo-timestep to update the timestep.
482: Collective on TS
484: Input Parameters:
485: + ts - timestep context
486: . dt - function to compute timestep
487: - ctx - [optional] user-defined context for private data
488: required by the function (may be PETSC_NULL)
490: Level: intermediate
492: Calling sequence of func:
493: . func (TS ts,PetscReal *newdt,void *ctx);
495: . newdt - the newly computed timestep
496: . ctx - [optional] timestep context
498: Notes:
499: The routine set here will be called by TSPseudoComputeTimeStep()
500: during the timestepping process.
502: .keywords: timestep, pseudo, set
504: .seealso: TSPseudoDefaultTimeStep(), TSPseudoComputeTimeStep()
505: @*/
506: PetscErrorCode TSPseudoSetTimeStep(TS ts,PetscErrorCode (*dt)(TS,PetscReal*,void*),void* ctx)
507: {
508: PetscErrorCode ierr,(*f)(TS,PetscErrorCode (*)(TS,PetscReal *,void *),void *);
513: PetscObjectQueryFunction((PetscObject)ts,"TSPseudoSetTimeStep_C",(void (**)(void))&f);
514: if (f) {
515: (*f)(ts,dt,ctx);
516: }
517: return(0);
518: }
520: /* ----------------------------------------------------------------------------- */
526: PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,void* ctx)
527: {
528: TS_Pseudo *pseudo;
531: pseudo = (TS_Pseudo*)ts->data;
532: pseudo->verify = dt;
533: pseudo->verifyctx = ctx;
534: return(0);
535: }
541: PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)
542: {
543: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
546: pseudo->dt_increment = inc;
547: return(0);
548: }
554: PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
555: {
556: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
559: pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
560: return(0);
561: }
568: PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,void* ctx)
569: {
570: TS_Pseudo *pseudo = (TS_Pseudo*)ts->data;
573: pseudo->dt = dt;
574: pseudo->dtctx = ctx;
575: return(0);
576: }
579: /* ----------------------------------------------------------------------------- */
580: /*MC
581: TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
583: This method solves equations of the form
585: $ F(X,Xdot) = 0
587: for steady state using the iteration
589: $ [G'] S = -F(X,0)
590: $ X += S
592: where
594: $ G(Y) = F(Y,(Y-X)/dt)
596: This is linearly-implicit Euler with the residual always evaluated "at steady
597: state". See note below.
599: Options database keys:
600: + -ts_pseudo_increment <real> - ratio of increase dt
601: - -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
603: Level: beginner
605: References:
606: Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential-Algebraic Equations, 2003.
607: C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
609: Notes:
610: The residual computed by this method includes the transient term (Xdot is computed instead of
611: always being zero), but since the prediction from the last step is always the solution from the
612: last step, on the first Newton iteration we have
614: $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
616: Therefore, the linear system solved by the first Newton iteration is equivalent to the one
617: described above and in the papers. If the user chooses to perform multiple Newton iterations, the
618: algorithm is no longer the one described in the referenced papers.
620: .seealso: TSCreate(), TS, TSSetType()
622: M*/
626: PetscErrorCode TSCreate_Pseudo(TS ts)
627: {
628: TS_Pseudo *pseudo;
632: ts->ops->destroy = TSDestroy_Pseudo;
633: ts->ops->view = TSView_Pseudo;
635: if (ts->problem_type == TS_LINEAR) {
636: SETERRQ(PETSC_ERR_ARG_WRONG,"Only for nonlinear problems");
637: }
638: if (!ts->Arhs) {
639: SETERRQ(PETSC_ERR_ARG_WRONGSTATE,"Must set Jacobian");
640: }
642: ts->ops->setup = TSSetUp_Pseudo;
643: ts->ops->step = TSStep_Pseudo;
644: ts->ops->setfromoptions = TSSetFromOptions_Pseudo;
646: /* create the required nonlinear solver context */
647: SNESCreate(((PetscObject)ts)->comm,&ts->snes);
648: PetscObjectIncrementTabLevel((PetscObject)ts->snes,(PetscObject)ts,1);
650: PetscNewLog(ts,TS_Pseudo,&pseudo);
651: ts->data = (void*)pseudo;
653: pseudo->dt_increment = 1.1;
654: pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
655: pseudo->dt = TSPseudoDefaultTimeStep;
657: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetVerifyTimeStep_C",
658: "TSPseudoSetVerifyTimeStep_Pseudo",
659: TSPseudoSetVerifyTimeStep_Pseudo);
660: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStepIncrement_C",
661: "TSPseudoSetTimeStepIncrement_Pseudo",
662: TSPseudoSetTimeStepIncrement_Pseudo);
663: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoIncrementDtFromInitialDt_C",
664: "TSPseudoIncrementDtFromInitialDt_Pseudo",
665: TSPseudoIncrementDtFromInitialDt_Pseudo);
666: PetscObjectComposeFunctionDynamic((PetscObject)ts,"TSPseudoSetTimeStep_C",
667: "TSPseudoSetTimeStep_Pseudo",
668: TSPseudoSetTimeStep_Pseudo);
669: return(0);
670: }
675: /*@C
676: TSPseudoDefaultTimeStep - Default code to compute pseudo-timestepping.
677: Use with TSPseudoSetTimeStep().
679: Collective on TS
681: Input Parameters:
682: . ts - the timestep context
683: . dtctx - unused timestep context
685: Output Parameter:
686: . newdt - the timestep to use for the next step
688: Level: advanced
690: .keywords: timestep, pseudo, default
692: .seealso: TSPseudoSetTimeStep(), TSPseudoComputeTimeStep()
693: @*/
694: PetscErrorCode 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;
701: TSComputeRHSFunction(ts,ts->ptime,ts->vec_sol,pseudo->func);
702: VecNorm(pseudo->func,NORM_2,&pseudo->fnorm);
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: return(0);
717: }