Skip to content

Dynamics

Lateral Spreading

As the jet decelerates, the sound speed in the shocked fluid becomes comparable to the bulk velocity, causing the jet to expand sideways. blastwave offers three spreading modes:

Mode spread_mode Description
PDE "pde" (default when spread=True) Finite-volume lateral transport; couples all \(\theta\)-cells through Godunov fluxes
ODE "ode" Per-cell velocity-driven expansion; cells evolve independently
None "none" or spread=False No spreading; each cell evolves as a spherical segment

The PDE mode captures lateral structure self-consistently through momentum and energy transport between cells. The ODE mode is faster and follows the standard analytic prescription where each cell's opening angle grows at the local sound speed.

from blastwave import Jet, TopHat, ForwardJetRes

P = dict(Eiso=1e52, lf=300, theta_c=0.1, n0=1.0, A=0.0,
         eps_e=0.1, eps_b=0.01, p=2.2, theta_v=0.0, d=474.33, z=0.1)

# PDE spreading (default)
jet_pde = Jet(TopHat(0.1, 1e52, lf0=300), 0.0, 1.0,
              grid=ForwardJetRes(0.1, 129),
              spread=True, spread_mode="pde",
              eps_e=0.1, eps_b=0.01, p_fwd=2.2)

# ODE spreading
jet_ode = Jet(TopHat(0.1, 1e52, lf0=300), 0.0, 1.0,
              grid=ForwardJetRes(0.1, 129),
              spread=True, spread_mode="ode",
              eps_e=0.1, eps_b=0.01, p_fwd=2.2)

t = np.geomspace(10, 1e8, 200)
flux_pde = jet_pde.FluxDensity(t, 1e9, P, model="sync_ssa_smooth")
flux_ode = jet_ode.FluxDensity(t, 1e9, P, model="sync_ssa_smooth")

Both modes produce a jet break — a steepening in the light curve at \(t_\mathrm{jet} \sim\) days to weeks — but differ in the post-break slope and transition sharpness. The PDE mode generally produces a smoother, more gradual break due to the lateral structure that develops self-consistently, while the ODE mode gives a sharper transition.

2026-03-05T23:03:37.808699 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/

Script: examples/showcase_dynamics.py


Reverse Shock

When the relativistic ejecta collide with the decelerated forward shock, a reverse shock propagates back through the ejecta shell. This produces an additional emission component that peaks at early times, particularly bright at radio and optical wavelengths.

Enable the reverse shock by passing shell and microphysics parameters to Jet():

jet = Jet(
    TopHat(0.1, 1e52, lf0=300), 0.0, 1.0,
    grid=ForwardJetRes(0.1, 129),
    spread=False,
    eps_e=0.1, eps_b=0.01, p_fwd=2.2,
    # Reverse shock parameters
    include_reverse_shock=True,
    duration=1000.0,        # engine activity time (s) — sets shell thickness
    sigma=0.0,              # ejecta magnetization (0 = unmagnetized)
    eps_e_rs=0.1,           # RS electron energy fraction
    eps_b_rs=0.01,          # RS magnetic energy fraction
    p_rs=2.2,               # RS electron spectral index
)

The duration parameter controls the shell thickness: longer duration means a thicker shell and a longer-lived reverse shock. The magnetization sigma affects the shock compression ratio and post-shock magnetic field.

Once the jet is created with include_reverse_shock=True, the emission can be decomposed:

flux_total   = jet.FluxDensity(t, 3e9, P, model="sync_ssa_smooth")         # FS + RS
flux_forward = jet.FluxDensity_forward(t, 3e9, P, model="sync_ssa_smooth")  # FS only
flux_reverse = jet.FluxDensity_reverse(t, 3e9, P, model="sync_ssa_smooth")  # RS only

The reverse shock component typically dominates the radio emission at \(t \lesssim 1\) day, producing a characteristic early-time bump before the forward shock takes over.

2026-03-05T23:03:42.944931 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/

Script: examples/showcase_dynamics.py


Energy Injection

blastwave supports energy injection from a central engine via a magnetar spin-down model. The injected luminosity follows:

\[ L(t) = \frac{L_0}{(1 + t/t_0)^q} \]

where \(L_0\) is the initial luminosity, \(t_0\) is the spin-down timescale, and \(q\) controls the decay steepness (\(q = 2\) for dipole radiation).

Energy injection sustains the blast wave against deceleration, producing an X-ray plateau (the luminosity stays roughly constant while injection dominates) and delayed radio re-brightening.

jet = Jet(
    TopHat(0.1, 1e52, lf0=100), 0.0, 1.0,
    grid=ForwardJetRes(0.1, 129),
    spread=False,
    eps_e=0.1, eps_b=0.01, p_fwd=2.2,
    magnetar_l0=1e47,   # injection luminosity (erg/s)
    magnetar_t0=1e4,    # spin-down timescale (s)
    magnetar_q=2,        # decay index
)

Multiple injection episodes can be specified by passing lists:

jet = Jet(...,
    magnetar_l0=[1e47, 1e46],   # two injection components
    magnetar_t0=[1e4, 1e6],
    magnetar_q=[2, 1.5],
    magnetar_ts=[0, 1e5],       # start times (s)
)

Note

Energy injection currently requires spread=False or spread_mode="ode". The PDE spread mode does not support injection.

2026-03-05T23:03:43.974137 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/

Script: examples/showcase_dynamics.py