Стаття Фізика та Механіка · ≈ 10 хв читання

Верле, Leapfrog та RK4: інтегратори для фізики

Метод Ейлера руйнує будь-яку фізичну симуляцію: пружини розтягуються в нескінченність, орбіти закручуються в спіраль. Розберемо, чому це відбувається — і які інтегратори насправді зберігають енергію та залишаються стабільними у реальному часі.

1. Проблема Ейлера

Метод Ейлера — найпростіший чисельний інтегратор: взяти поточне значення похідної і перемножити на крок часу.

Явний метод Ейлера (Forward Euler) v(t + dt) = v(t) + a(t) · dt
x(t + dt) = x(t) + v(t) · dt

Проблема в тому, що Ейлер не зберігає повну механічну енергію системи. У Гамільтонових системах (маятник, орбіти, пружини) метод Ейлера систематично додає або забирає енергію на кожному кроці. Результат: пружина нескінченно розтягується, а планета закручується в спіраль замість того, щоб залишатися на орбіті.

Чому це критично?

Для виглядаючих реалістично симуляцій тканини, маятників, рідини — Euler непридатний навіть при малому dt. Через 100–1000 кроків система «вибухає» або «замерзає».

Метод Ейлера має першосортну локальну похибку O(dt²) і глобальну похибку O(dt). Щоб зменшити похибку вдвічі, треба зменшити крок вдвічі — і вдвічі більше роботи. Це не вирішує проблему нестабільності.

2. Метод Верле

Люк Верле запропонував метод у 1967 році для молекулярної динаміки. Ключова ідея: обчислювати позицію через дві попередні позиції, уникаючи прямого зберігання швидкості.

Виводимо з розкладу Тейлора: запишемо x(t+dt) і x(t-dt), потім складемо:

Метод Верле x(t+dt) = 2·x(t) − x(t−dt) + a(t)·dt²

Де a(t) = F(t)/m — прискорення у поточний момент. Швидкість у цій формулі явно не фігурує, але може бути отримана апроксимацією:

Апроксимація швидкості (для відображення) v(t) ≈ [x(t+dt) − x(t−dt)] / (2·dt)

Метод Верле є симплектичним — він точно зберігає симплектичну форму фазового простору, що для Гамільтонових систем означає збереження енергії на довгих горизонтах. Його глобальна похибка — O(dt²), як і в Ейлера, але без зростаючого зміщення енергії.

Слабке місце

Стандартний Верле не підходить для нестаціонарних сил (залежних від швидкості: демпфування, опір середовища), бо v доступна лише апроксимовано. Крім того, перший крок потребує x(-dt) — зазвичай отриманого з x(0) + v(0)·dt назад.

3. Velocity Verlet

Velocity Verlet — модифікований метод Верле, де швидкість зберігається явно. Алгоритм двокроковий:

Velocity Verlet (два кроки) Крок 1 — нова позиція:
x(t+dt) = x(t) + v(t)·dt + ½·a(t)·dt²

Крок 2 — нова швидкість:
v(t+dt) = v(t) + ½·[a(t) + a(t+dt)]·dt

Зверніть увагу: між кроками потрібно перерахувати a(t+dt) з нової позиції. Тобто сила обчислюється двічі за ітерацію. Але Velocity Verlet точно підтримує v — що критично для симуляцій тканини, де пружинна сила залежить від v (демпфування).

Velocity Verlet — стандарт для рушіїв типу Cannon-es, Bullet, Havok завдяки точному v і відмінній стабільності.

4. Leapfrog-інтегратор

Leapfrog («жаб'ячий стрибок») — ще одна форма того ж симплектичного методу. Позиція та швидкість зсунуті на половину кроку відносно одна одної, як два жабяти що стрибають по черзі:

Leapfrog / Störmer–Verlet v(t + ½dt) = v(t − ½dt) + a(t) · dt
x(t + dt) = x(t) + v(t + ½dt) · dt

Алгоритм обчислює прискорення лише один раз за крок (на відміну від Velocity Verlet), тому він вдвічі дешевший за обчисленнями. Саме тому Leapfrog є стандартом для N-тіл та молекулярної динаміки.

Drift-Kick-Drift (DKD)

Leapfrog можна записати у так званій DKD-формі — «дрейф-удар-дрейф» — щоб стартувати з цілого часового кроку:

DKD — симетрична форма x ← x + v · (dt/2)    (Drift)
v ← v + a(x) · dt    (Kick)
x ← x + v · (dt/2)    (Drift)
Реальне застосування

Leapfrog використовується у всіх великих N-тіл кодах (GADGET, RAMSES, ChaNGa) і в симуляції N-тіл цього проєкту. Він зберігає момент імпульсу і кутовий момент до машинної точності.

5. Runge-Kutta 4-го порядку (RK4)

RK4 — найвідоміший загальний метод чисельного інтегрування ОДУ. Він оцінює похідну у чотирьох точках всередині кроку і береже зважене середнє:

RK4 — чотири оцінки k₁ = f(t, y)      ← початок
k₂ = f(t+dt/2, y + k₁·dt/2)    ← середина (через k₁)
k₃ = f(t+dt/2, y + k₂·dt/2)    ← середина (через k₂)
k₄ = f(t+dt, y + k₃·dt)     ← кінець

y(t+dt) = y(t) + (k₁ + 2k₂ + 2k₃ + k₄) · dt/6

RK4 має глобальну похибку O(dt⁴) — при зменшенні кроку вдвічі похибка зменшується у 16 разів. Він ідеальний для хаотичних систем (атрактор Лоренца, подвійний маятник), де потрібна висока точність траєкторії за відносно короткий час.

RK4 vs Leapfrog: важливий нюанс

RK4 НЕ є симплектичним. На тривалих горизонтах він роздає або забирає енергію — гірше, ніж Leapfrog. Для планетарних орбіт чи тривалих симуляцій Leapfrog буде стабільнішим незважаючи на нижчий порядок точності.

RK4 обчислює f() чотири рази за крок — це вчетверо дорожче за Leapfrog. Але він незамінний для жорстких систем (stiff ODEs) і там, де траєкторія важлива сама по собі (подвійний маятник, атрактор Лоренца).

6. Порівняння методів

МетодПорядокСимплект.F/крокКоли використовувати
Euler (явний) O(dt) 1 Ніколи для фізики (тільки прототипи)
Symplectic Euler O(dt) 1 Проста ігрова фізика, дуже малий dt
Verlet (базовий) O(dt²) 1 Молдин. без швидкісних сил
Velocity Verlet O(dt²) 2 Тканина, пружини з демпфуванням, Cannon-es
Leapfrog (DKD) O(dt²) 1 N-тіла, молек. динаміка, планети
RK4 O(dt⁴) 4 Хаотичні системи, атрактор Лоренца, маятник

7. Коли що використовувати

Ігрова фізика реального часу (60 FPS)

Для ігрових рушіїв та інтерактивних симуляцій з великим dt (1/60 с = 16.7 мс) — Velocity Verlet або Symplectic Euler. Вони симплектичні, дешеві і достатньо точні. Cannon-es використовує Symplectic Euler зі split impulse для тіл.

Тканина та м'які тіла

Velocity Verlet: демпфування пружин залежить від швидкості — потрібне явне v. Position-Based Dynamics (PBD) використовує скорочену форму Верле: оновлює позиції без пружних сил, потім виконує constraint projection.

N-тіла та молекулярна динаміка

Leapfrog / Störmer-Verlet. Мільярди кроків у MD-симуляціях — тому дешевизна (1 обчислення F/крок) та збереження енергії критично важливі.

Хаотичні атрактори, подвійний маятник

RK4. Траєкторія важлива сама по собі — потрібна висока точність на кожному кроці. Та й горизонт відносно короткий (секунди або хвилини).

8. Псевдокод

Velocity Verlet (JS)

// Velocity Verlet — тканина, маятник
function stepVelocityVerlet(particles, dt) {
  for (const p of particles) {
    // Крок 1: оновити позицію
    p.x += p.vx * dt + 0.5 * p.ax * dt * dt;
    p.y += p.vy * dt + 0.5 * p.ay * dt * dt;

    // Зберегти старе прискорення
    const ax0 = p.ax, ay0 = p.ay;

    // Крок 2: перерахувати сили з нової позиції
    computeForces(particles);

    // Крок 3: оновити швидкість через середнє прискорення
    p.vx += 0.5 * (ax0 + p.ax) * dt;
    p.vy += 0.5 * (ay0 + p.ay) * dt;
  }
}

Leapfrog DKD (JS)

// Leapfrog — N-тіла, планети
function stepLeapfrog(bodies, dt) {
  const hdt = dt / 2;

  // Drift (D): половина кроку позиція
  for (const b of bodies) {
    b.x += b.vx * hdt;
    b.y += b.vy * hdt;
  }

  // Kick (K): повний крок швидкість
  computeGravity(bodies);            // → b.ax, b.ay
  for (const b of bodies) {
    b.vx += b.ax * dt;
    b.vy += b.ay * dt;
  }

  // Drift (D): ще половина кроку позиція
  for (const b of bodies) {
    b.x += b.vx * hdt;
    b.y += b.vy * hdt;
  }
}

RK4 для ОДУ (JS)

// RK4 — атрактор Лоренца, подвійний маятник
function rk4(state, deriv, dt) {
  const k1 = deriv(state);
  const k2 = deriv(add(state, scale(k1, dt/2)));
  const k3 = deriv(add(state, scale(k2, dt/2)));
  const k4 = deriv(add(state, scale(k3, dt)));

  // Зважене середнє: 1/6 · (k1 + 2k2 + 2k3 + k4)
  return add(state, scale(
    add(k1, add(scale(k2, 2), add(scale(k3, 2), k4))),
    dt / 6
  ));
}

// Допоміжні функції для векторних операцій
const add   = (a, b) => a.map((v, i) => v + b[i]);
const scale = (a, s) => a.map(v => v * s);

Побачте інтегратори в дії

Симуляція N-тіл використовує Leapfrog. Подвійний маятник — RK4. Тканина — Velocity Verlet.

⭐ N-тіл (Leapfrog) 🌀 Маятник (RK4)