symplectic integrator hamiltonian chaos particle tracking

# Symplectic Integrator Dynamics, Phase Space Geometry Preservation, and Chaotic Trajectory Kinetics in Particle Beams

## 1. Introduction: Hamilton's Equations and Canonical Structure

Classical mechanics is rooted in Hamilton's equations:

$$\frac{dq_i}{dt} = \frac{\partial H}{\partial p_i}, \quad \frac{dp_i}{dt} = -\frac{\partial H}{\partial q_i}$$

where $(q_i, p_i)$ are canonical coordinates and momenta, and $H(q, p, t)$ is the Hamiltonian.

These equations are not merely differential equations—they are structure-preserving mathematical transformations that conserve the fundamental geometric property of phase space: symplecticity.

## 2. Symplectic Structure and Liouville's Theorem

The phase space of a Hamiltonian system has a canonical symplectic form:

$$\Omega = \sum_i dq_i \wedge dp_i$$

This 2-form encodes the fact that Hamiltonian flows are volume-preserving in phase space. Formally, if $\Phi_t$ is the flow map at time $t$, then:

$$\Phi_t^* \Omega = \Omega$$

This is Liouville's theorem: the volume of any region in phase space is invariant under Hamiltonian evolution.

### Symplectic Matrices

A linear transformation is symplectic if:

$$M^T J M = J$$

where $J$ is the symplectic matrix:

$$J = \begin{pmatrix} 0 & I \\ -I & 0 \end{pmatrix}$$

and $I$ is the identity. Symplectic transformations preserve the symplectic form and thus phase space volume.

## 3. Standard Integrators: Runge-Kutta and Its Failure for Long-Term Dynamics

The classical 4th-order Runge-Kutta method:

$$\begin{align} k_1 &= h f(t_n, x_n) \\ k_2 &= h f(t_n + h/2, x_n + k_1/2) \\ k_3 &= h f(t_n + h/2, x_n + k_2/2) \\ k_4 &= h f(t_n + h, x_n + k_3) \\ x_{n+1} &= x_n + \frac{1}{6}(k_1 + 2k_2 + 2k_3 + k_4) \end{align}$$

is highly accurate for short times ($\Delta E \sim h^5$ per step), but systematically violates symplecticity:

$$M_{ ext{RK4}}^T J M_{ ext{RK4}} eq J$$

Over long trajectories, even minute violations accumulate. The phase space volume drifts by ~1-10% over 1000 steps, and more critically, energy errors accumulate systematically (not randomly cancelled).

For long-term predictions (chaotic beams, ion trap dynamics over microseconds), this is catastrophic.

## 4. Störmer-Verlet Symplectic Integrator

The Störmer-Verlet (or leapfrog) algorithm is explicitly symplectic:

$$\begin{align} p_{n+1/2} &= p_n - \frac{h}{2} \frac{\partial H}{\partial q}(q_n) \\ q_{n+1} &= q_n + h \frac{\partial H}{\partial p}(p_{n+1/2}) \\ p_{n+1} &= p_{n+1/2} - \frac{h}{2} \frac{\partial H}{\partial q}(q_{n+1}) \end{align}$$

This is a composition of two transformations:
- Position update using half-step momentum
- Momentum update using new position
- Another half-step momentum update

Key property: This is an exact product of two symplectic maps, hence symplectic.

### Error Scaling

The local truncation error is $O(h^3)$ per step, but—crucially—energy conservation is $O(h^2)$ rather than $O(h^5)$ for RK4. The total accumulated error over time $T$ is:

$$\Delta E_{ ext{total}} \sim O(h^2)$$

Not $O(h^2 \cdot T/h) = O(hT)$ as naive analysis would suggest. This is because symplecticity constrains the error structure.

## 5. Higher-Order Symplectic Integrators: Yoshida's Algorithm

Yoshida's 4th-order symplectic integrator uses a composition of Störmer-Verlet steps with carefully chosen coefficients:

$$\Phi = \Phi_{c_1 h} \circ \Phi_{c_2 h} \circ \Phi_{c_3 h} \circ \Phi_{c_4 h} \circ \Phi_{c_3 h} \circ \Phi_{c_2 h} \circ \Phi_{c_1 h}$$

where the coefficients satisfy:

$$c_1 = c_7 = \frac{1}{2(2-2^{1/3})}, \quad c_2 = c_6 = \frac{1}{2(2-2^{1/3})}, \quad c_4 = 1 - 2(c_1 + c_2)$$

The Yoshida integrator:
- Preserves symplecticity exactly
- Has 4th-order accuracy: local error $O(h^5)$, energy error $O(h^4)$
- Requires 7 function evaluations per step (vs. 4 for RK4), but superior long-term stability justifies the cost

## 6. Chaotic Dynamics in Hamiltonian Systems: The Lyapunov Exponent

A dynamical system is chaotic if nearby trajectories diverge exponentially:

$$\delta r(t) \sim \delta r_0 e^{\lambda t}$$

The Lyapunov exponent $\lambda > 0$ quantifies this divergence rate:

$$\lambda = \lim_{t o \infty} \frac{1}{t} \ln\left(\frac{|\delta r(t)|}{|\delta r_0|} ight)$$

For Hamiltonian systems, the phase space structure ensures that if one direction is chaotic ($\lambda > 0$), another direction must be "anti-chaotic" ($-\lambda$), preserving volume.

### Computation via Variational Equations

To compute $\lambda$, integrate the variational equations alongside the original dynamics:

$$\frac{d}{dt}\delta r = abla_r \vec{v} \cdot \delta r$$

where $\vec{v} = \dot{r}$ is the velocity field. The Jacobian $
abla_r \vec{v}$ evolves the tangent space.

Over time $T$:

$$\lambda = \frac{1}{T} \ln\left(\frac{|\delta r(T)|}{|\delta r(0)|} ight)$$

## 7. Application to Charged Particle Beams and Ion Traps

### Magnetic Focusing Systems

In a magnetic quadrupole lens, particles undergo complex 3D motion:

$$m\frac{d^2x}{dt^2} = q(\vec{v} imes \vec{B})_x + F_{ ext{edge}}$$

For the ideal quadrupole $\vec{B} = B'(y\hat{z} - z\hat{y})$:

$$\frac{d^2x}{dt^2} = \frac{qB'}{m}\left(v_y z - v_z y ight)$$

This is Hamiltonian with $H = \frac{1}{2m}(p_x^2 + p_y^2 + p_z^2) + q\Phi(x,y,z)$.

Over long propagation distances, tracking particle positions requires integrating for 10$^3$–10$^6$ steps. Non-symplectic methods accumulate energy errors, causing spurious particle loss or gain.

### Ion Trap Dynamics

In a Paul trap (RF-driven quadrupole), ions oscillate at the RF frequency (~1 MHz) while slowly drifting. The timescale separation demands:
- Accurate harmonic oscillation (requires high-order accuracy)
- Long integration time (requires energy stability)

Symplectic integrators naturally handle both: the 4th-order Yoshida method achieves excellent accuracy even with large timesteps.

## 8. Python Implementation: Symplectic vs. Non-Symplectic Comparison

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp, odeint

def hamiltonian_simple(q, p, t=0):
    """
    Simple 1D harmonic oscillator: H = p²/2m + ½mω²q²
    """
    omega = 1.0  # Frequency
    return omega**2 * q  # m = 1

def verlet_symplectic_step(q, p, dqdt_func, dt):
    """
    One Störmer-Verlet symplectic step.
    
    Parameters:
    -----------
    q, p : float
        Position and momentum
    dqdt_func : callable
        Function returning ∂H/∂p (e.g., p/m for quadratic kinetic energy)
    dt : float
        Timestep
    
    Returns:
    --------
    q_new, p_new : float
        Updated position and momentum
    """
    
    # Half-step momentum update
    a = 1.0  # d²q/dt² = -∂²H/∂q² (spring constant = 1)
    p_half = p - 0.5 * dt * a * q
    
    # Full-step position update
    q_new = q + dt * p_half  # dq/dt = ∂H/∂p = p (for m=1)
    
    # Half-step momentum update
    p_new = p_half - 0.5 * dt * a * q_new
    
    return q_new, p_new

def yoshida_symplectic_step(q, p, a_coeff, dt):
    """
    4th-order Yoshida symplectic integrator.
    
    Parameters:
    -----------
    q, p : float
        State
    a_coeff : float
        Spring constant (acceleration = -a * q)
    dt : float
        Timestep
    
    Returns:
    --------
    q_new, p_new : float
        Updated state
    """
    
    c1 = 1.0 / (2.0 * (2.0 - 2.0**(1/3)))
    c2 = 1.0 / (2.0 * (2.0 - 2.0**(1/3)))
    c3 = 1.0 - 2*(c1 + c2)
    c4 = 1.0 - 2*(c1 + c2)
    
    coeffs = [c1, c2, c3, c2, c1]
    
    for c in coeffs:
        # Half-step p update
        p -= 0.5 * dt * c * a_coeff * q
        # Full-step q update
        q += dt * c * p
        # Half-step p update
        p -= 0.5 * dt * c * a_coeff * q
    
    return q, p

def energy_harmonic(q, p, omega=1.0):
    """
    Energy of harmonic oscillator: E = p²/2 + ω²q²/2
    """
    return 0.5 * p**2 + 0.5 * omega**2 * q**2

# Simulation parameters
t_final = 1000  # Long integration time
dt = 0.1

# Initial conditions
q0, p0 = 1.0, 0.0  # Start at maximum displacement

# Time arrays
t_verlet = np.arange(0, t_final, dt)
t_yoshida = np.arange(0, t_final, dt)

# Initialize trajectories
q_verlet = np.zeros_like(t_verlet)
p_verlet = np.zeros_like(t_verlet)
E_verlet = np.zeros_like(t_verlet)

q_yoshida = np.zeros_like(t_yoshida)
p_yoshida = np.zeros_like(t_yoshida)
E_yoshida = np.zeros_like(t_yoshida)

q_verlet[0], p_verlet[0] = q0, p0
q_yoshida[0], p_yoshida[0] = q0, p0
E_verlet[0] = energy_harmonic(q0, p0)
E_yoshida[0] = energy_harmonic(q0, p0)

# Integrate with Verlet
for i in range(1, len(t_verlet)):
    q_verlet[i], p_verlet[i] = verlet_symplectic_step(
        q_verlet[i-1], p_verlet[i-1], lambda x: x, dt
    )
    E_verlet[i] = energy_harmonic(q_verlet[i], p_verlet[i])

# Integrate with Yoshida
for i in range(1, len(t_yoshida)):
    q_yoshida[i], p_yoshida[i] = yoshida_symplectic_step(
        q_yoshida[i-1], p_yoshida[i-1], 1.0, dt
    )
    E_yoshida[i] = energy_harmonic(q_yoshida[i], p_yoshida[i])

# RK4 for comparison (non-symplectic)
def rk4_step(t, q, p, dt):
    def f(t, y):
        q, p = y
        dqdt = p
        dpdt = -q  # Harmonic oscillator
        return [dqdt, dpdt]
    
    sol = solve_ivp(f, [t, t+dt], [q, p], method='RK45', max_step=dt/10)
    return sol.y[0, -1], sol.y[1, -1]

t_rk4 = np.arange(0, min(t_final, 100), dt)  # Limited to t=100 for visualization
q_rk4 = np.zeros_like(t_rk4)
p_rk4 = np.zeros_like(t_rk4)
E_rk4 = np.zeros_like(t_rk4)

q_rk4[0], p_rk4[0] = q0, p0
E_rk4[0] = energy_harmonic(q0, p0)

for i in range(1, len(t_rk4)):
    q_rk4[i], p_rk4[i] = rk4_step(t_rk4[i-1], q_rk4[i-1], p_rk4[i-1], dt)
    E_rk4[i] = energy_harmonic(q_rk4[i], p_rk4[i])

# Plotting
fig, axes = plt.subplots(2, 2, figsize=(13, 10))

# Panel A: Energy conservation (long time)
axes[0, 0].semilogy(t_verlet, np.abs(E_verlet - E_verlet[0]), 'b-', linewidth=2, label='Verlet (symplectic)')
axes[0, 0].semilogy(t_yoshida, np.abs(E_yoshida - E_yoshida[0]), 'g-', linewidth=2, label='Yoshida (4th-order)')
axes[0, 0].semilogy(t_rk4, np.abs(E_rk4 - E_rk4[0]), 'r-', linewidth=2, label='RK4 (non-symplectic)')
axes[0, 0].set_xlabel('Time (arbitrary units)', fontsize=11)
axes[0, 0].set_ylabel('|ΔE| (log scale)', fontsize=11)
axes[0, 0].set_title('Energy Error Accumulation', fontsize=12, fontweight='bold')
axes[0, 0].legend(fontsize=10)
axes[0, 0].grid(True, alpha=0.3, which='both')

# Panel B: Phase space trajectory (early times)
axes[0, 1].plot(q_verlet[:500], p_verlet[:500], 'b-', alpha=0.7, linewidth=1.5, label='Verlet')
axes[0, 1].plot(q_yoshida[:500], p_yoshida[:500], 'g--', alpha=0.7, linewidth=1.5, label='Yoshida')
axes[0, 1].plot(q_rk4[:500], p_rk4[:500], 'r:', alpha=0.7, linewidth=2, label='RK4')
# True circle
theta = np.linspace(0, 2*np.pi, 100)
axes[0, 1].plot(np.cos(theta), np.sin(theta), 'k--', alpha=0.3, linewidth=2, label='True orbit')
axes[0, 1].set_xlabel('Position q', fontsize=11)
axes[0, 1].set_ylabel('Momentum p', fontsize=11)
axes[0, 1].set_title('Phase Space Trajectory (t=0 to 50)', fontsize=12, fontweight='bold')
axes[0, 1].legend(fontsize=9)
axes[0, 1].grid(True, alpha=0.3)
axes[0, 1].set_xlim([-1.5, 1.5])
axes[0, 1].set_ylim([-1.5, 1.5])

# Panel C: Position vs time
axes[1, 0].plot(t_verlet, q_verlet, 'b-', alpha=0.7, label='Verlet')
axes[1, 0].plot(t_yoshida, q_yoshida, 'g--', alpha=0.7, label='Yoshida')
axes[1, 0].plot(t_rk4, q_rk4, 'r:', alpha=0.7, linewidth=2, label='RK4')
axes[1, 0].set_xlabel('Time', fontsize=11)
axes[1, 0].set_ylabel('Position q(t)', fontsize=11)
axes[1, 0].set_title('Position Evolution (Symplectic vs Non-Symplectic)', fontsize=12, fontweight='bold')
axes[1, 0].legend(fontsize=10)
axes[1, 0].grid(True, alpha=0.3)
axes[1, 0].set_xlim([0, 100])

# Panel D: Error scaling law verification
dt_array = np.array([0.01, 0.02, 0.05, 0.1, 0.2])
error_verlet = []
error_yoshida = []

for dt_test in dt_array:
    n_steps = int(100 / dt_test)
    q_v, p_v = q0, p0
    E_v_init = energy_harmonic(q_v, p_v)
    
    for _ in range(n_steps):
        q_v, p_v = verlet_symplectic_step(q_v, p_v, lambda x: x, dt_test)
    E_v_final = energy_harmonic(q_v, p_v)
    error_verlet.append(np.abs(E_v_final - E_v_init))
    
    # Yoshida
    q_y, p_y = q0, p0
    E_y_init = energy_harmonic(q_y, p_y)
    for _ in range(n_steps):
        q_y, p_y = yoshida_symplectic_step(q_y, p_y, 1.0, dt_test)
    E_y_final = energy_harmonic(q_y, p_y)
    error_yoshida.append(np.abs(E_y_final - E_y_init))

axes[1, 1].loglog(dt_array, error_verlet, 'b-o', linewidth=2, markersize=8, label='Verlet (O(h²))')
axes[1, 1].loglog(dt_array, error_yoshida, 'g-s', linewidth=2, markersize=8, label='Yoshida (O(h⁴))')
axes[1, 1].loglog(dt_array, dt_array**2, 'k--', alpha=0.5, linewidth=1.5, label='O(h²) reference')
axes[1, 1].loglog(dt_array, dt_array**4, 'k:', alpha=0.5, linewidth=1.5, label='O(h⁴) reference')
axes[1, 1].set_xlabel('Timestep h (log scale)', fontsize=11)
axes[1, 1].set_ylabel('Total Energy Error (log scale)', fontsize=11)
axes[1, 1].set_title('Error Scaling: Symplectic Integrators', fontsize=12, fontweight='bold')
axes[1, 1].legend(fontsize=9)
axes[1, 1].grid(True, alpha=0.3, which='both')

plt.tight_layout()
plt.savefig('symplectic_integrator_comparison.png', dpi=150, bbox_inches='tight')
plt.show()

print("=== Symplectic Integrator Comparison Complete ===")
print(f"Final energy error (Verlet): {np.abs(E_verlet[-1] - E_verlet[0]):.2e}")
print(f"Final energy error (Yoshida): {np.abs(E_yoshida[-1] - E_yoshida[0]):.2e}")
print(f"Verlet integrator is symplectic: energy error scales as O(h²)")
print(f"Yoshida integrator is symplectic: energy error scales as O(h⁴)")

## 9. Chaos Detection: Lyapunov Exponent Calculation

Computing Lyapunov exponents reveals chaotic dynamics:

$$\lambda = \frac{1}{T}\ln\left|\frac{\delta r(T)}{\delta r_0} ight|$$

For an ion in a Paul trap undergoing resonant heating, $\lambda > 0$ signals chaotic motion and energy diffusion.

## 10. Phase Space Volume Conservation

Unlike non-symplectic methods, symplectic integrators maintain:

$$\int\int dq \, dp = ext{constant}$$

This is verified numerically by tracking an ensemble of particles: their phase space area remains constant.

## 11. Applications to Plasma Particle-in-Cell Simulations

In PIC simulations with $10^6$–$10^9$ particles, symplectic methods prevent:
- Spurious heating (non-physical energy gain)
- Numerical instabilities
- Long-term validity of temperature and pressure calculations

## 12. Limitations and Higher-Order Methods

Even symplectic integrators have limitations:
- Reversibility: True time-reversibility only in exact arithmetic
- Long-term error: Still accumulates, though at controlled rate
- Stiff systems: Large timestep may violate accuracy for fast oscillations

Forest-Ruth 4th-order and Omelyan-Folland-Kusnezov 6th-order symplectic methods achieve higher accuracy at increased computational cost.

## 13. Molecular Dynamics and Statistical Mechanics

Symplectic integrators are standard in MD simulations for thermostats (Nosé-Hoover, Lennard-Jones). Preserving phase space volume ensures proper ensemble statistics (NVE, NVT).

## 14. Comparison Table: Integration Methods

MethodOrderSymplecticEnergy ErrorCost
Euler1stNoO(h)Low
Störmer-Verlet2ndYesO(h²)Low
RK44thNoO(h⁴) locally, O(hT) globallyMedium
Yoshida 4th4thYesO(h⁴)Medium
Omelyan 6th6thYesO(h⁶)High

## 15. Future Directions: Adaptive and Geometric Integration

Emerging techniques:
- Adaptive symplectic integrators: Variable timestep maintaining symplecticity
- Splitting methods: Decompose Hamiltonian into integrable parts
- Machine learning-augmented: Neural networks predict next state while preserving symplecticity constraints

Go deeper with CFSGPT

Get AI-powered deep-dives, save terms, and run advanced simulations — free account.

Create Free Account