Heun Method

Essence. The Heun method is a simple improvement over the Euler method. Instead of relying solely on the derivative at the initial point \( \mathbf{x}_n \), it uses the average slope at the beginning and at the end of the time step \( \Delta t \). For a system \( \dot{\mathbf{x}} = f(\mathbf{x}, t, \theta) \), the method first performs an Euler step (the predictor): \( \mathbf{x}_{n+1}^{(p)} = \mathbf{x}_n + \Delta t\, f(\mathbf{x}_n) \), and then corrects this result (the corrector): \( \mathbf{x}_{n+1} = \mathbf{x}_n + \tfrac{\Delta t}{2}\big[ f(\mathbf{x}_n) + f(\mathbf{x}_{n+1}^{(p)}) \big] \). Instead of assuming a constant slope across the entire interval (as in Euler), Heun's method averages the slope from the beginning and the end of the step. This yields a significantly lower global error than Euler, while keeping the computational cost relatively small.

Example. For the equation \( \dot{x} = -2x \) with initial condition \( x_0 = 1 \) and time step \( \Delta t = 0.1 \). Each step consists of two stages: predictor and corrector.

Step 1 (from \( x_0 \) to \( x_1 \)). Derivative at \( x_0 = 1 \): \( f(x_0) = -2 \cdot 1 = -2 \) (predictor), predictor value: \( x_{1}^{(p)} = x_0 + 0.1 \cdot (-2) = 0.8 \), derivative at the predicted point \( x_{1}^{(p)} = 0.8 \): \( f(x_{1}^{(p)}) = -2 \cdot 0.8 = -1.6 \). New approximation (average slope): \( x_1 = x_0 + \tfrac{0.1}{2}\big[ f(x_0) + f(x_{1}^{(p)}) \big] = 1 + 0.05 \cdot (-2 - 1.6) = 0.82. \)

Step 2 (from \( x_1 \) to \( x_2 \)). Predictor: \( f(x_1) = -2 \cdot 0.82 = -1.64 \), \( x_{2}^{(p)} = 0.82 + 0.1 \cdot (-1.64) = 0.656 \). Corrector: \( f(x_{2}^{(p)}) = -2 \cdot 0.656 = -1.312 \), \( x_2 = 0.82 + 0.05 \cdot (-1.64 - 1.312) \approx 0.6724. \)

Further steps proceed in the same way: first compute the derivative at \( x_n \), then perform an Euler step to obtain \( x_{n+1}^{(p)} \), and finally correct the result by averaging the slopes at both points. Compared to the Euler method, the resulting sequence \( x_n \) is closer to the exact solution even for the same time step \( \Delta t \).

Usage. The Heun method offers a good balance between simplicity and accuracy. It typically produces more stable trajectories than Euler, especially for moderately sized time steps. In chaotic systems one must still choose \( \Delta t \) carefully, but for many attractors the Heun method yields visibly “cleaner” trajectories than Euler for the same step size. In practice, Heun is useful when Euler produces excessive distortion or when one wants a quick improvement in accuracy without moving to higher-order methods such as RK4 or Dormand–Prince.

Implementation. In the Attractor Builder add-on, each Heun step is performed by the function step_heun. Unlike Euler, which uses only the derivative at the current point, Heun computes the derivative twice: at the current point and at the predicted point (the predictor). The implementation is:

def step_heun(rhs_func, p: Vector, params: dict, dt: float): p_pred = p + rhs_func(p, params) * dt avg_slope = 0.5 * (rhs_func(p, params) + rhs_func(p_pred, params)) return p + avg_slope * dt

The algorithm proceeds as follows:
1. Compute the derivative at the current point \( p \): \( f(p) = rhs\_func(p, params) \).
2. Predictor (Euler step): \( p^{(p)} = p + \Delta t \, f(p) \).
3. Compute the derivative at the predicted point \( p^{(p)} \): \( f(p^{(p)}) \).
4. Average the slopes: \( \tfrac{1}{2}[ f(p) + f(p^{(p)}) ] \).
5. Compute the new point: \( p_{n+1} = p + \Delta t \cdot \tfrac{1}{2}[ f(p) + f(p^{(p)}) ] \). For example, in the Attractor Builder we choose the Lorenz system:

Equations:
dx/dt = a * (y - x)
dy/dt = x * (b - z) - y
dz/dt = x * y - c * z

Parameters:
| a = 10 | b = 28 | c = 8/3 |

Simulation settings:
Initial state: x₀ = 0.01, y₀ = 0.01, z₀ = 0.01
Method: Heun
Time step (dt): 0.01
Number of steps: 3
Burn-in: 0
Scale: 1
Step 1. Initial point: x0 = 0.01; y0 = 0.01; z0 = 0.01.
Derivatives:
dx0 = 10*(y0 - x0) = 10*(0.01 - 0.01) = 0
dy0 = x0*(28 - z0) - y0 = 0.01*(28 - 0.01) - 0.01 = 0.2699
dz0 = x0*y0 - (8/3)*z0 ≈ 0.0001 - 0.02667 ≈ -0.02657

Predictor (Euler):
x_pred = x0 + 0.01*dx0 = 0.01
y_pred = y0 + 0.01*dy0 = 0.01 + 0.01*0.2699 ≈ 0.01270
z_pred = z0 + 0.01*dz0 ≈ 0.01 + 0.01*(-0.02657) ≈ 0.00973

Derivatives at predicted point (rounded):
dxp = 10*(y_pred - x_pred) ≈ 10*(0.01270 - 0.01) ≈ 0.0270
dyp ≈ 0.2672
dzp ≈ -0.0258

Average slopes:
dx_avg ≈ (dx0 + dxp)/2 ≈ 0.0135
dy_avg ≈ (dy0 + dyp)/2 ≈ 0.2686
dz_avg ≈ (dz0 + dzp)/2 ≈ -0.0262

New point (after Step 1):
x1 ≈ 0.0101349
y1 ≈ 0.0126855
z1 ≈ 0.0097380

Step 2. Starting point: x1 ≈ 0.0101349; y1 ≈ 0.0126855; z1 ≈ 0.0097380.
[compute predictor, derivatives, and average slope analogously]
New point:
x2 ≈ 0.0105128
y2 ≈ 0.0154176
z2 ≈ 0.0094832

Step 3. Starting point: x2 ≈ 0.0105128; y2 ≈ 0.0154176; z2 ≈ 0.0094832.
After applying the predictor and corrector:
x3 ≈ 0.0111181
y3 ≈ 0.0182607
z3 ≈ 0.0092354

At each step, the algorithm first computes the derivative vector at the current point (predictor, equivalent to Euler), then computes it again at the predicted point and averages the two slopes. This produces a trajectory that better reflects the true shape of the attractor compared to a simple Euler method with the same time step \( \Delta t \).