У своїй відповіді на запитання про MSE щодо 2D-моделювання фізики Гамільтонів я запропонував використовувати симплектичний інтегратор вищого порядку .
Тоді я подумав, що може бути гарною ідеєю продемонструвати вплив різних часових кроків на глобальну точність методів з різними порядками, і я написав і запустив сценарій Python / Pylab для цього ефекту. Для порівняння я вибрав:
- ( leap2 ) Приклад Вікіпедії 2-го порядку, з яким я знайомий, хоча я знаю його під назвою leapfrog ,
- ( ruth3 ) Симплектичний інтегратор Рут 3-го порядку ,
- ( ruth4 ) Симплектичний інтегратор Рут четвертого порядку .
Дивна річ у тому, який би часовий крок я не вибрав, метод Рут 3-го порядку здається більш точним у моєму тесті, ніж метод Рут 4-го порядку, навіть на порядок.
Моє запитання тому: що я тут роблю неправильно? Деталі нижче.
Методи розгортають свою силу в системах з відокремленими гамільтоніанами, тобто в тих, які можна записати як
У нашому налаштуванні ми можемо нормалізувати сили та імпульси за допомогою мас, до яких вони застосовуються. Таким чином сили перетворюються на прискорення, а моменти перетворюються на швидкості.
Симплектична інтегратори йдуть зі спеціальними (враховуючи, постійні) коефіцієнти , які я маркують і . З цими коефіцієнтами один крок для розвитку системи від часу до часу приймає форму
Для :
- Обчисліть вектор всіх прискорень, задавши вектор усіх положень
- Змініть вектор усіх швидкостей на
- Зміна вектора всіх позицій по
Мудрість тепер полягає в коефіцієнтах. Це
Для тестування я вибрав задачу з початковим значенням 1D
Я інтегрував IVP з вищезазначеними методами над зі ступенем розміру з цілим числомобраним десь між і . Враховуючи швидкість стрибка2 , я потроїв для цього методу. Потім я побудував отримані криві у фазовому просторі і збільшив масштаб де криві в ідеалі повинні знову прийти до .
Ось графіки та масштаби для та :
Для , стрибок2 з розміром кроку
Ось сценарій Python / Pylab:
import numpy as np
import matplotlib.pyplot as plt
def symplectic_integrate_step(qvt0, accel, dt, coeffs):
q,v,t = qvt0
for ai,bi in coeffs.T:
v += bi * accel(q,v,t) * dt
q += ai * v * dt
t += ai * dt
return q,v,t
def symplectic_integrate(qvt0, accel, t, coeffs):
q = np.empty_like(t)
v = np.empty_like(t)
qvt = qvt0
q[0] = qvt[0]
v[0] = qvt[1]
for i in xrange(1, len(t)):
qvt = symplectic_integrate_step(qvt, accel, t[i]-t[i-1], coeffs)
q[i] = qvt[0]
v[i] = qvt[1]
return q,v
c = np.math.pow(2.0, 1.0/3.0)
ruth4 = np.array([[0.5, 0.5*(1.0-c), 0.5*(1.0-c), 0.5],
[0.0, 1.0, -c, 1.0]]) / (2.0 - c)
ruth3 = np.array([[2.0/3.0, -2.0/3.0, 1.0], [7.0/24.0, 0.75, -1.0/24.0]])
leap2 = np.array([[0.5, 0.5], [0.0, 1.0]])
accel = lambda q,v,t: -q
qvt0 = (1.0, 0.0, 0.0)
tmax = 2.0 * np.math.pi
N = 36
fig, ax = plt.subplots(1, figsize=(6, 6))
ax.axis([-1.3, 1.3, -1.3, 1.3])
ax.set_aspect('equal')
ax.set_title(r"Phase plot $(y(t),y'(t))$")
ax.grid(True)
t = np.linspace(0.0, tmax, 3*N+1)
q,v = symplectic_integrate(qvt0, accel, t, leap2)
ax.plot(q, v, label='leap2 (%d steps)' % (3*N), color='black')
t = np.linspace(0.0, tmax, N+1)
q,v = symplectic_integrate(qvt0, accel, t, ruth3)
ax.plot(q, v, label='ruth3 (%d steps)' % N, color='red')
q,v = symplectic_integrate(qvt0, accel, t, ruth4)
ax.plot(q, v, label='ruth4 (%d steps)' % N, color='blue')
ax.legend(loc='center')
fig.show()
Я вже перевірив прості помилки:
- Немає друку у Вікіпедії. Я перевірив посилання, зокрема ( 1 , 2 , 3 ).
- Я правильно зрозумів послідовність коефіцієнтів. Якщо ви порівнюєте з замовленням Вікіпедії, зауважте, що послідовність роботи програми оператора працює справа наліво. Моя нумерація погоджується з Candy / Rozmus . І якщо я все ж спробую інше замовлення, результати погіршаться.
Мої підозри:
- Неправильний тест: Щось особливе в моєму тесті дозволяє методу Рут 3-го порядку вести себе як метод вищого порядку?