Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Part 4: Stability Analysis

Module 3: ODE Methods & Conservation | ASTR 596

San Diego State University

Learning Outcomes

By the end of this section, you will be able to:


Linear Stability Theory

To understand when methods fail catastrophically, we analyze their behavior on the test equation:

dydt=λy\frac{dy}{dt} = \lambda y

where λC\lambda \in \mathbb{C}. The true solution is y(t)=y0eλty(t) = y_0 e^{\lambda t}.

When we apply a numerical method, we get:

yn+1=R(hλ)yny_{n+1} = R(h\lambda) y_n

where R(z)R(z) is the stability function with z=hλz = h\lambda.

For bounded solutions, we need R(hλ)1|R(h\lambda)| \leq 1. The stability region is the set of zz values where this holds.

Stability Functions for Common Methods

Let’s derive the stability functions for our methods:

Euler’s Method

Applying Euler to y=λyy' = \lambda y:

yn+1=yn+hλyn=(1+hλ)yny_{n+1} = y_n + h\lambda y_n = (1 + h\lambda)y_n

Therefore: R(z)=1+z\boxed{R(z) = 1 + z}

This is stable when 1+z1|1 + z| \leq 1, which defines a circle of radius 1 centered at z=1z = -1.

RK2 (Midpoint)

Following through the RK2 steps:

k1=λynk_1 = \lambda y_n

k2=λ(yn+h2k1)=λyn(1+z2)k_2 = \lambda(y_n + \frac{h}{2}k_1) = \lambda y_n(1 + \frac{z}{2})

yn+1=yn+hk2=yn(1+z+z22)y_{n+1} = y_n + hk_2 = y_n(1 + z + \frac{z^2}{2})

Therefore: R(z)=1+z+z22\boxed{R(z) = 1 + z + \frac{z^2}{2}}

RK4

Through similar analysis (but more algebra):

R(z)=1+z+z22+z36+z424\boxed{R(z) = 1 + z + \frac{z^2}{2} + \frac{z^3}{6} + \frac{z^4}{24}}

This matches the Taylor series of eze^z through fourth order, but is not exactly eze^z truncated!

Physical Interpretation

For different types of problems, we need different stability characteristics:

Oscillatory Systems (Circular Orbits)

For a harmonic oscillator with frequency ω\omega:

Dissipative Systems (Damped Motion)

For exponential decay with rate γ\gamma:

Stiff Equations - When Stability Dominates

What Makes an Equation Stiff?

A stiff equation contains widely separated timescales. After fast transients die out, we’re left tracking slow evolution, but explicit methods still need tiny timesteps for stability.

Understanding Stiffness Through Examples

Example 1: Chemical Kinetics

Consider a reaction where species A slowly converts to B, but B rapidly equilibrates:

dAdt=0.04A\frac{dA}{dt} = -0.04A
dBdt=0.04A104B\frac{dB}{dt} = 0.04A - 10^4 B

The eigenvalues are λ1=0.04\lambda_1 = -0.04 (slow) and λ2=104\lambda_2 = -10^4 (fast).

After the initial transient (t>0.001t > 0.001), B has equilibrated and we’re just tracking the slow decay of A. But explicit methods need h<2/104=0.0002h < 2/10^4 = 0.0002 for stability, even though nothing interesting happens on this timescale!

Example 2: Stellar Interior with Radiative Cooling

In stellar shocks, radiative cooling can create extreme stiffness:

dTdt=heatingcooling(T)\frac{dT}{dt} = \text{heating} - \text{cooling}(T)

where cooling T4\propto T^4 for high temperatures. Near equilibrium:

Non-Stiff vs Stiff: The Key Distinction

Non-stiff equations have eigenvalues with similar magnitudes. The timestep is chosen for accuracy, and stability is automatically satisfied. Examples:

Stiff equations have eigenvalues with vastly different magnitudes. The timestep is forced by stability of the fastest mode, even after it has decayed. Examples:

Implicit Methods for Stiff Problems

Implicit methods evaluate the derivative at the future point, giving superior stability at the cost of solving equations.

Backward Euler

Instead of yn+1=yn+hf(yn,tn)y_{n+1} = y_n + hf(y_n, t_n), we use:

yn+1=yn+hf(yn+1,tn+1)\boxed{y_{n+1} = y_n + hf(y_{n+1}, t_{n+1})}

This is implicit because yn+1y_{n+1} appears on both sides!

Stability Analysis

For the test equation y=λyy' = \lambda y:

yn+1=yn+hλyn+1y_{n+1} = y_n + h\lambda y_{n+1}

yn+1(1hλ)=yny_{n+1}(1 - h\lambda) = y_n

yn+1=yn1hλy_{n+1} = \frac{y_n}{1 - h\lambda}

Stability function: R(z)=11z\boxed{R(z) = \frac{1}{1-z}}

This is stable for the entire left half-plane! We call this A-stable.

Solving the Implicit Equation

The challenge: we must solve yn+1=yn+hf(yn+1,tn+1)y_{n+1} = y_n + hf(y_{n+1}, t_{n+1}) for yn+1y_{n+1}.

For nonlinear ff, this requires iteration. Newton’s method is typical:

def backward_euler_step(y, t, h, f, df_dy, tol=1e-10):
    """
    Single backward Euler step
    Requires Jacobian df/dy for Newton iteration
    """
    y_new = y  # Initial guess
    
    for _ in range(10):  # Newton iterations
        # Residual: R(y_new) = y_new - y - h*f(y_new, t+h)
        residual = y_new - y - h*f(y_new, t + h)
        
        if np.linalg.norm(residual) < tol:
            return y_new
        
        # Jacobian of residual
        J = np.eye(len(y)) - h*df_dy(y_new, t + h)
        
        # Newton update
        delta = np.linalg.solve(J, -residual)
        y_new = y_new + delta
    
    raise RuntimeError("Newton iteration failed to converge")

Implicit Midpoint Rule

A second-order implicit method:

yn+1=yn+hf(yn+yn+12,tn+h2)y_{n+1} = y_n + hf\left(\frac{y_n + y_{n+1}}{2}, t_n + \frac{h}{2}\right)

This is A-stable AND symplectic! It preserves geometric structure while handling stiffness.

The CFL Condition

The CFL condition is a necessary stability criterion for hyperbolic PDEs that also applies to ODEs from spatial discretization:

hΔxcmaxh \leq \frac{\Delta x}{c_{max}}

where Δx\Delta x is the spatial grid spacing and cmaxc_{max} is the maximum wave speed.

For the wave equation 2ut2=c22ux2\frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2} discretized in space:

This means finer spatial grids require smaller timesteps!

Diagnosing Integration Problems

Systematic Debugging Approach

When your integration fails, follow this diagnostic sequence:

  1. Check for NaN/Inf: Immediate indicator of instability

  2. Plot the solution: Look for oscillations growing exponentially

  3. Compute eigenvalues: Estimate λmax\lambda_{max}

  4. Check stability limit: Is hλmax<stability limith|\lambda_{max}| < \text{stability limit}?

  5. Test with smaller h: Does halving h fix the problem?

  6. Monitor energy: For conservative systems, is energy bounded?

Stability Test Code

def stability_test(method, lambda_val, h_values):
    """Test stability for different timesteps"""
    results = []
    
    for h in h_values:
        y = 1.0  # Initial condition
        stable = True
        
        for n in range(1000):
            y = method(y, lambda_val, h)
            
            if abs(y) > 1e10:  # Explosion detected
                stable = False
                break
        
        results.append((h, stable, abs(y)))
    
    return results

Bridge to Part 5: From Stability to Speed

Understanding stability tells us what timesteps are allowed, but performance determines whether our simulations finish in reasonable time. Even the most stable method is useless if it takes years to run.

In Part 5, we’ll explore performance optimization through vectorization. Modern processors can perform multiple operations simultaneously, but only if we structure our code correctly. The difference between naive loops and optimized array operations can be 100× in execution speed—the difference between waiting hours and waiting weeks for results.

Next: Part 5 - Performance Optimization