Time Integration
The dream.time module provides the time-stepping infrastructure that is shared across all
dream solvers. It separates two concerns:
A
TimeSchemesdiscretizes the time derivative of the semi-discrete problem arising from the spatial discretization and advances the solution by a single time level or Runge-Kutta stage. Concrete schemes (explicit, implicit, IMEX) are implemented per solver, e.g. indream.scalar_transport.timeanddream.compressible_flow.conservative.time.A
TimeRoutinedrives the overall solution process: it owns the main solution loop, manages I/O, and reports solver convergence. The available routines areStationaryRoutine,TransientRoutine,PseudoTimeSteppingRoutine, and the IMEX routines derived fromIMEXTimeRoutine.
Stationary and transient routines
For steady-state problems, StationaryRoutine solves the discrete problem
directly, without time-stepping. For time-dependent problems, TransientRoutine
marches the solution forward over a fixed time interval \((t_0, t_{\mathrm{end}})\) held by a
Timer, advancing \(t_n \to t_{n+1} = t_n + \Delta t\) until \(t_{\mathrm{end}}\) is
reached. PseudoTimeSteppingRoutine instead marches a stationary problem towards
steady state using pseudo-time continuation, in which an artificial time derivative is added and the
(pseudo) time step is progressively increased, improving the robustness of the nonlinear solver when
starting far from the solution.
Geometry-split implicit-explicit (IMEX) time integration
In many flow problems, only a small part of the computational mesh is responsible for the
geometry-induced stiffness that limits the stable time step of an explicit scheme, for example highly
refined regions near walls or small geometric features. The IMEX routines derived from
IMEXTimeRoutine exploit this by coupling two independently configured
SolverConfigurations, held by an IMEXTimeRoutine as cfg_implicit and
cfg_explicit. The routine itself does not partition a mesh into implicit/explicit regions; rather, it
assumes that the two complementary meshes,
with interface \(\Gamma_i\), have already been constructed and assigned to cfg_implicit and
cfg_explicit, respectively, e.g. with the stiff (typically small) region assigned to cfg_implicit
and the remaining, non-stiff region to cfg_explicit. Stiff regions are typically discretized with an
implicit Hybridised Discontinuous Galerkin (HDG) scheme, while non-stiff regions are discretized with
a (standard) discontinuous Galerkin (DG) scheme; however, the routine itself only assumes that
cfg_implicit is solved implicitly and cfg_explicit explicitly in time, not any specific spatial
discretization. In particular, both regions may equally well use a DG discretization, with only the
time treatment (implicit vs. explicit) differing between them.
The two solutions are coupled weakly and conservatively across \(\Gamma_i\) by appropriate interface conditions, while the temporal synchronization between the implicit and explicit schemes is achieved through additive Runge-Kutta (ARK) methods: the implicit part is advanced with a singly diagonally implicit Runge-Kutta (SDIRK) method, and the explicit part with a standard explicit Runge-Kutta (ERK) method. At every stage, the explicit solution is updated first, using the implicit solution of the previous stage, and the implicit solution is then updated using the just-computed explicit solution.
Two synchronization strategies are available:
SynchronizedIMEXTimeRoutine: the implicit and explicit schemes share the same (global) time step \(\Delta t\) and their stage times coincide, \(\overline{c}_{i+1} = c_i\), following the classical structure of an ARK method. This is the strategy used for the ARS-type IMEX schemes for compressible flows.PCIMEXTimeRoutineandLinearPCIMEXTimeRoutine: a predictor-corrector strategy in which the global (implicit) time step may be a larger integer multiple of the local (explicit) time step, allowing the explicit scheme to sub-cycle within an implicit stage. During the sub-cycling, the interface value provided to the explicit scheme is either held frozen at \(\vec{U}_n^{im}\) (PCIMEXTimeRoutine) or linearly interpolated in time between the implicit solution at the start and end of the stage (LinearPCIMEXTimeRoutine), before the implicit (corrector) solution is recomputed using the updated explicit state.
By restricting the (more expensive) implicit solve to the stiff region \(\mesh^{im}\), while advancing the remainder of the domain \(\mesh^{ex}\) with the cheaper explicit scheme, the IMEX approach increases the overall stable time step compared to a fully explicit discretization, at the cost of the additional implicit solve. The net benefit therefore depends both on an effective mesh partitioning and an efficient implicit solver.
|
Keeps track of the simulation time and time step used by a |
|
Base interface for a spatial/temporal discretization scheme. |
|
Base interface for a concrete (multi-step or multi-stage) time-stepping scheme. |
|
Base interface for a top-level solution routine driving a |
|
Solves a stationary (steady-state) problem. |
|
Marches a time-dependent problem forward over a fixed time interval. |
|
Marches a stationary problem to steady state using pseudo-time continuation. |
|
Base interface for a geometry-split implicit-explicit (IMEX) time routine. |
|
IMEX routine in which the implicit and explicit schemes share the same time step and stage times. |
|
IMEX predictor-corrector routine with frozen interface values during the predictor stage. |
|
IMEX predictor-corrector routine with linear interpolation of interface values. |
- class Timer(mesh=None, root=None, **default)
Keeps track of the simulation time and time step used by a
TimeRoutine.The timer holds the time interval \((t_0, t_{\mathrm{end}})\) to be simulated, the current simulation time \(t\) and the time step \(\Delta t\). Calling the timer as a generator, see
__call__(), advances \(t\) from \(t_0\) to \(t_{\mathrm{end}}\) in increments of \(\Delta t\), yielding the iteration number together with the time levels \(t_n\) and \(t_{n+1}\) bracketing each step.- property interval: tuple[float, float]
Sets the time interval \((t_0, t_{\mathrm{end}})\) to be simulated.
- Getter:
Returns the time interval
- Setter:
Sets the time interval, defaults to (0.0, 1.0)
- property step: Parameter
Sets the time step \(\Delta t\) used to advance the simulation.
- Getter:
Returns the time step
- Setter:
Sets the time step, defaults to 1e-4
- property t: Parameter
Sets the current simulation time \(t\).
- Getter:
Returns the current simulation time
- Setter:
Sets the current simulation time, defaults to 0.0
- class Scheme(mesh, root=None, **default)
Base interface for a spatial/temporal discretization scheme.
A
Schemeis responsible for assembling the bilinear and linear forms of the discretized problem, seeassemble(), and for solving either a stationary problem, seesolve_stationary(), or a single time level/stage, seeTimeSchemes.- property compile: dict[str, bool]
Sets the NGSolve compile options used when assembling the symbolic forms.
- Getter:
Returns the compile options
- Setter:
Sets the compile options, defaults to False
- parse_sum_of_integrals(integrals: dict[str, dict[str, SumOfIntegrals]], include_spaces: tuple[str, ...] = None, exclude_spaces: tuple[str, ...] = None, include_terms: tuple[str, ...] = None, exclude_terms: tuple[str, ...] = None) dict[str, dict[str, SumOfIntegrals]]
Parse the sum of integrals dictionary to include or exclude specific spaces and terms.
By default, it includes all spaces and terms in the integrals. You can specify which spaces to include or exclude, and which terms to include or exclude. If a space in the include container is not found in the integrals dictionary, it will raise an error.
- class TimeSchemes(mesh, root=None, **default)
Base interface for a concrete (multi-step or multi-stage) time-stepping scheme.
A
TimeSchemesdiscretizes the time derivative of the semi-discrete problem and advances the solution either over a single time level, seesolve_current_time_level(), or over a single Runge-Kutta stage, seesolve_stage(). Multi-step schemes (e.g. BDF) keep track of the solutions of the previousnumber_of_stepstime levels viaget_step_gridfunctions(), while multi-stage schemes (e.g. Runge-Kutta) evaluate the right-hand side at the intermediate stage times given bytime_of_stages.Concrete implementations are provided per solver, e.g. in
dream.scalar_transport.timeanddream.compressible_flow.conservative.time.- update_final_stage_solution() None
Updates the final stage solution
This method is needed in case the time scheme is not stiffly accurate.
- class TimeRoutine(mesh: Mesh, root: Configuration = None, **default)
Base interface for a top-level solution routine driving a
SolverConfiguration.While a
TimeSchemesdiscretizes a single time level or stage, aTimeRoutineorchestrates the full solution process, i.e. it drives the main solution loop, seestart_solution_routine(), manages I/O, and reports solver convergence, seeparse_routine_log(). Available routines areStationaryRoutine,TransientRoutine,PseudoTimeSteppingRoutine, and the IMEX routines derived fromIMEXTimeRoutine.- parse_routine_log(it: int | None = None, error: float | None = None, t: float | None = None, stage: int | None = None, cfg: SolverConfiguration = None, **kwargs)
Parse the routine log and return a formatted string.
- class StationaryRoutine(mesh: Mesh, root: Configuration = None, **default)
Solves a stationary (steady-state) problem.
No time integration is performed: the routine simply assembles the discrete problem and solves it via the nonlinear solver of the underlying scheme, see
Scheme.solve_stationary().
- class TransientRoutine(mesh, root=None, **default)
Marches a time-dependent problem forward over a fixed time interval.
The routine repeatedly advances the solution from \(t_n\) to \(t_{n+1} = t_n + \Delta t\) over the interval held by its
timer, seestart_solution_routine(). Each time level is solved by the scheme of the underlyingSolverConfiguration, seeTimeSchemes.solve_current_time_level(). In addition to the standard solution routine, this class providesstart_timing_solution_routine()for performance profiling, andfind_stable_time_step()to determine, by bisection, the largest stable time step for an explicit scheme.
- class PseudoTimeSteppingRoutine(mesh, root=None, **default)
Marches a stationary problem to steady state using pseudo-time continuation.
Rather than solving the nonlinear stationary problem directly, an artificial (pseudo) time derivative is added and advanced with a time step that is progressively increased, every
increment_atiterations, byincrement_factor, up tomax_time_step. This continuation strategy improves the robustness of the nonlinear solver, especially when starting far from the steady-state solution, seesolver_iteration_update().- property timer: Timer
Sets the timer holding the pseudo-time step and current pseudo-time.
- Getter:
Returns the timer
- Setter:
Sets the timer, defaults to
Timer
- property max_time_step: float
Sets the upper bound the pseudo-time step is allowed to grow to.
- Getter:
Returns the maximum pseudo-time step
- Setter:
Sets the maximum pseudo-time step, defaults to 1.0
- property increment_at: int
Sets the number of iterations after which the pseudo-time step is increased.
- Getter:
Returns the increment interval
- Setter:
Sets the increment interval, defaults to 10
- property increment_factor: int
Sets the multiplicative factor applied to the pseudo-time step at each increment.
- Getter:
Returns the increment factor
- Setter:
Sets the increment factor, defaults to 10
- class IMEXTimeRoutine(cfg_implicit: SolverConfiguration, cfg_explicit: SolverConfiguration, **default)
Base interface for a geometry-split implicit-explicit (IMEX) time routine.
An
IMEXTimeRoutinecouples two independently configured solvers,cfg_implicitandcfg_explicit, each holding its ownSolverConfigurationand mesh. The routine itself does not partition a mesh into implicit/explicit regions; rather, it assumes that the two complementary meshes \(\mesh^{im}\) and \(\mesh^{ex}\), with interface \(\Gamma_i = \mesh^{im} \cap \mesh^{ex}\), have already been constructed and assigned to cfg_implicit and cfg_explicit, respectively, e.g. with the stiff (typically small) region assigned to cfg_implicit and the remaining, non-stiff region to cfg_explicit.Stiff regions are typically treated implicitly using a hybridizable discontinuous Galerkin (HDG) scheme, while non-stiff regions are treated explicitly using a (standard) discontinuous Galerkin (DG) scheme; however, the routine itself only assumes that cfg_implicit is solved implicitly and cfg_explicit explicitly in time, and not any specific spatial discretization. In particular, both regions may equally well use a DG discretization, with only the time treatment (implicit vs. explicit) differing between them. The two solutions are weakly and conservatively coupled across \(\Gamma_i\) by appropriate interface conditions, while temporal synchronization between the implicit and explicit schemes is achieved through additive Runge-Kutta (ARK) methods, in which the implicit part is a singly diagonally implicit Runge-Kutta (SDIRK) method and the explicit part a standard explicit Runge-Kutta (ERK) method.
At each global time step, every stage is solved by first advancing the explicit region, see
solve_explicit_stage(), and then the implicit region, seesolve_implicit_stage(), such that the explicit stage uses the implicit solution at the previous stage, and the implicit stage uses the just-updated explicit solution, seesolve_stages().Restricting the (typically more expensive) implicit scheme to a small region, while advancing the bulk of the domain with the cheaper explicit scheme, allows the explicit scheme’s stable time step to increase compared to a fully explicit discretization of the whole domain; this increase yields the overall speedup of the IMEX approach, at the cost of the additional implicit solve. Two synchronization strategies are provided:
SynchronizedIMEXTimeRoutine, in which the implicit and explicit schemes share the same time step and stage times, and the predictor-corrector routinesPCIMEXTimeRoutine/LinearPCIMEXTimeRoutine, which allow the explicit scheme to sub-cycle with a smaller, locally defined time step.- property gscheme: TimeSchemes
Global implicit scheme.
- property lscheme: TimeSchemes
Local explicit scheme.
- update_final_stage_solution() None
Updates the final stage solution
This method is needed in case the time scheme is not stiffly accurate.
- class SynchronizedIMEXTimeRoutine(cfg_implicit: SolverConfiguration, cfg_explicit: SolverConfiguration, **default)
IMEX routine in which the implicit and explicit schemes share the same time step and stage times.
Both the implicit and explicit schemes advance with the same (global) time step \(\Delta t\) and the additive Runge-Kutta tableaux are synchronized via padding, i.e. the stage times coincide, \(\overline{c}_{i+1} = c_i\). This is the classical structure of an ARK method and is the synchronization strategy used for the geometry-split IMEX schemes (ARS-type) developed for compressible flows in
IMEXTimeRoutine.At every stage \(i\), the explicit stage solution is computed first, see
solve_explicit_stage(), followed by the implicit stage solution, seesolve_implicit_stage(), both using the previously computed stage solution of the other scheme. The final solution update accounts for the first-same-as-last (FSAL) property of the explicit scheme and the stiff accuracy of the implicit scheme, seeupdate_final_stage_solution().- update_final_stage_solution()
Updates the final stage solution
This method is needed in case the time scheme is not stiffly accurate.
- class PCIMEXTimeRoutine(cfg_implicit: SolverConfiguration, cfg_explicit: SolverConfiguration, **default)
IMEX predictor-corrector routine with frozen interface values during the predictor stage.
Unlike
SynchronizedIMEXTimeRoutine, the global (implicit) time step \(\Delta t\) need not equal the local (explicit) time step, but must be an integer multiple of it, allowing the explicit scheme to sub-cycle with several smaller steps per implicit stage.For each implicit stage, a predictor step first advances the implicit solution, see
solve_predictor_stage(), and the explicit scheme is then sub-cycled across the stage interval using the predicted interface value frozen at \(\vec{U}_n^{im}\) for all explicit sub-steps, seeset_predictor_solution(). The implicit (corrector) solution is finally recomputed using the now up-to-date explicit interface state, seesolve_implicit_stage().- update_final_stage_solution()
Updates the final stage solution
This method is needed in case the time scheme is not stiffly accurate.
- class LinearPCIMEXTimeRoutine(cfg_implicit: SolverConfiguration, cfg_explicit: SolverConfiguration, **default)
IMEX predictor-corrector routine with linear interpolation of interface values.
Extends
PCIMEXTimeRoutineby replacing the frozen interface value during the predictor stage with a linear interpolation in time. The predictor stage first solves the implicit scheme to obtain a prediction of the interface state at the end of the stage, seesolve_predictor_stage(), and the explicit sub-steps then use values linearly interpolated, based on the local sub-step time, between the implicit solution at the start (\(\vec{y}_1\)) and end (\(\vec{y}_2\)) of the stage, seeset_predictor_solution(). The corrector step, seesolve_implicit_stage(), resets the implicit solution to \(\vec{y}_1\) and resolves the implicit stage using the now updated explicit solution, improving accuracy compared to the frozen-interface predictor ofPCIMEXTimeRoutine.