Skip to main content

Overview

The timesteppers module provides implicit-explicit (IMEX) time integration schemes for solving initial value problems. These schemes treat stiff linear terms implicitly and nonlinear terms explicitly.

IMEX Multistep Methods

Multistep schemes use multiple previous timesteps to achieve higher order accuracy.

SBDF1

SBDF1
1st-order semi-implicit backward difference formula.
  • Order: 1
  • Implicit: 1st-order BDF (backward Euler)
  • Explicit: 1st-order extrapolation (forward Euler)
  • Steps: 1

Example

import dedalus.public as d3

solver = problem.build_solver(d3.SBDF1)  
solver.stop_sim_time = 10.0
dt = 0.01

while solver.proceed:
    solver.step(dt)

SBDF2

SBDF2
2nd-order semi-implicit BDF scheme.
  • Order: 2
  • Implicit: 2nd-order BDF
  • Explicit: 2nd-order extrapolation
  • Steps: 2
  • Startup: Uses SBDF1 for first step

Example

import dedalus.public as d3

solver = problem.build_solver(d3.SBDF2)  

SBDF3

SBDF3
3rd-order semi-implicit BDF scheme.
  • Order: 3
  • Implicit: 3rd-order BDF
  • Explicit: 3rd-order extrapolation
  • Steps: 3
  • Startup: Uses SBDF2, then SBDF1

SBDF4

SBDF4
4th-order semi-implicit BDF scheme.
  • Order: 4
  • Implicit: 4th-order BDF
  • Explicit: 4th-order extrapolation
  • Steps: 4
  • Startup: Uses SBDF3, SBDF2, SBDF1

Example

import dedalus.public as d3

# High-order timestepping  
solver = problem.build_solver(d3.SBDF4)

CNAB1

CNAB1
1st-order Crank-Nicolson Adams-Bashforth.
  • Order: 1
  • Implicit: 2nd-order Crank-Nicolson
  • Explicit: 1st-order Adams-Bashforth (forward Euler)
  • Steps: 1

CNAB2

CNAB2
2nd-order Crank-Nicolson Adams-Bashforth.
  • Order: 2
  • Implicit: 2nd-order Crank-Nicolson
  • Explicit: 2nd-order Adams-Bashforth
  • Steps: 2
  • Startup: Uses CNAB1

Example

import dedalus.public as d3

solver = problem.build_solver(d3.CNAB2)  

MCNAB2

MCNAB2
2nd-order modified Crank-Nicolson Adams-Bashforth.
  • Order: 2
  • Implicit: 2nd-order modified Crank-Nicolson
  • Explicit: 2nd-order Adams-Bashforth
  • Steps: 2

CNLF2

CNLF2
2nd-order Crank-Nicolson leap-frog.
  • Order: 2
  • Implicit: Wide Crank-Nicolson
  • Explicit: 2nd-order leap-frog
  • Steps: 2

IMEX Runge-Kutta Methods

Runge-Kutta schemes achieve high-order accuracy with intermediate stages within each timestep.

RK111

RK111  
1st-order 1-stage DIRK+ERK scheme.
  • Order: 1
  • Stages: 1
  • Type: DIRK (Diagonally Implicit) + ERK (Explicit)

RK222

RK222
2nd-order 2-stage DIRK+ERK scheme.
  • Order: 2
  • Stages: 2
  • Type: L-stable DIRK + ERK

Example

import dedalus.public as d3

# Good general-purpose scheme
solver = problem.build_solver(d3.RK222)

RK443

RK443
3rd-order 4-stage DIRK+ERK scheme.
  • Order: 3
  • Stages: 4
  • Type: L-stable DIRK + ERK

Example

import dedalus.public as d3

# Higher-order RK scheme
solver = problem.build_solver(d3.RK443)

RKSMR

RKSMR
(3-ε)-order 3-stage scheme (Spalart-Moser-Rogers).
  • Order: ~3
  • Stages: 3
  • Note: Optimized for DNS of turbulence

Example

import dedalus.public as d3

# Often used for turbulence simulations
solver = problem.build_solver(d3.RKSMR)

RKGFY

RKGFY
2nd-order 2-stage scheme (Hollerbach-Marti).
  • Order: 2
  • Stages: 2

Usage Examples

Basic Timestepping

import dedalus.public as d3
import numpy as np

# Setup problem (heat equation)
coord = d3.Coordinate('x')
dist = d3.Distributor(coord)  
xbasis = d3.ChebyshevT(coord, size=64, bounds=(0, 1))

u = dist.Field(bases=xbasis, name='u')
τ1 = dist.Field(name='τ1')
τ2 = dist.Field(name='τ2')  

ν = 0.01
problem = d3.IVP([u, τ1, τ2], namespace=locals())
problem.add_equation("dt(u) - ν*dx(dx(u)) + lift(τ1,-1) + lift(τ2,+1) = 0")
problem.add_equation("u(x='left') = 0")  
problem.add_equation("u(x='right') = 0")

# Initial condition
x = dist.local_grid(xbasis)
u['g'] = np.sin(np.pi * x)

# Create solver with timestepper  
solver = problem.build_solver(d3.RK222)
solver.stop_sim_time = 1.0

# Timestepping loop
dt = 0.001
while solver.proceed:
    solver.step(dt)  

Variable Timesteps

import dedalus.public as d3
import numpy as np

solver = problem.build_solver(d3.RK443)
solver.stop_sim_time = 10.0

# CFL-based timestepping  
CFL_safety = 0.5
max_dt = 0.1

while solver.proceed:
    # Compute CFL timestep
    dt_CFL = CFL_safety / np.max(CFL['g'])
    dt = min(dt_CFL, max_dt)  
    
    solver.step(dt)

Comparison of Schemes

import dedalus.public as d3

# First-order (for very stiff problems or startup)  
solver = problem.build_solver(d3.SBDF1)

# Second-order (good general purpose)
solver = problem.build_solver(d3.RK222)   # RK: better stability
solver = problem.build_solver(d3.SBDF2)   # Multistep: more efficient  

# Third-order (higher accuracy)
solver = problem.build_solver(d3.RK443)
solver = problem.build_solver(d3.SBDF3)

# Fourth-order (maximum accuracy)  
solver = problem.build_solver(d3.SBDF4)

Timestepper Selection Guide

For Stiff Problems

  • SBDF2, SBDF3, SBDF4: BDF schemes have excellent stability
  • RK222, RK443: Good L-stability properties

For Smooth Problems

  • CNAB2: Efficient for moderately stiff problems
  • RK443: Good accuracy with moderate stiffness

For Turbulence/DNS

  • RKSMR: Optimized for turbulent flows
  • RK443: Good high-order alternative

Computational Cost

Multistep (SBDF, CNAB):
  • Lower cost per timestep
  • Require storing previous steps
  • Startup overhead with lower-order schemes
Runge-Kutta (RK):
  • Higher cost per timestep (multiple stages)
  • Self-starting
  • Better for variable timesteps

See Also

Build docs developers (and LLMs) love