Dans ma réponse à une question sur MSE concernant une simulation physique hamiltonienne 2D, j'ai suggéré d'utiliser un intégrateur symplectique d' ordre supérieur .
Ensuite, j'ai pensé que ce pourrait être une bonne idée de démontrer les effets de différents pas de temps sur la précision globale des méthodes avec différents ordres, et j'ai écrit et exécuté un script Python / Pylab à cet effet. Pour comparaison j'ai choisi:
- ( leap2 ) Exemple de second ordre de Wikipédia que je connais bien que je le connaisse sous le nom de leapfrog ,
- ( ruth3 ) L'intégrateur symplectique de 3e ordre de Ruth ,
- ( ruth4 ) L'intégrateur symplectique de 4ème ordre de Ruth .
Ce qui est étrange, quel que soit le pas de temps que je choisis, la méthode de 3e ordre de Ruth semble être plus précise dans mon test que la méthode de 4e ordre de Ruth, même d'un ordre de grandeur.
Ma question est donc la suivante: que fais-je de mal ici? Détails ci-dessous.
Les méthodes déploient leur force dans des systèmes avec des hamiltoniens séparables , c'est-à-dire ceux qui peuvent être écrits comme
où comprend toutes les coordonnées de position,
comprend les moments conjugués,
représente la cinétique énergie et énergie potentielle
Dans notre configuration, nous pouvons normaliser les forces et les impulsions par les masses auxquelles elles sont appliquées. Ainsi, les forces se transforment en accélérations et les impulsions se transforment en vitesses.
Les intégrateurs symplectiques sont livrés avec des coefficients spéciaux (donnés, constants) que je et . Avec ces coefficients, une étape pour faire évoluer le système du temps au temps prend la forme
Pour :
- Calculer le vecteur de toutes les accélérations, étant donné le vecteur de toutes les positions
- Changer le vecteur de toutes les vitesses de
- Changer le vecteur de toutes les positions par
La sagesse réside maintenant dans les coefficients. Ce sont
Pour les tests, j'ai choisi le problème de valeur initiale 1D
qui a un hamiltonien séparable. Ici, sont identifiés par .
J'ai intégré l'IVP avec les méthodes ci-dessus sur avec un pas de avec un entier choisi entre et . Compte tenu de la vitesse de leap2 , j'ai triplé pour cette méthode. J'ai ensuite tracé les courbes résultantes dans l'espace des phases et zoomé à où les courbes devraient idéalement arriver à nouveau à .N(1,0)t=2π
Voici des tracés et des zooms pour et :
Pour , le saut 2 avec la taille de pas arrive plus près de la maison que ruth4 avec la taille de pas . Pour , ruth4 l' emporte sur leap2 . Cependant, ruth3 , avec la même taille de pas que ruth4 , arrive beaucoup plus près de chez nous que les deux autres, dans tous les paramètres que j'ai testés jusqu'à présent.2 π 2π
Voici le script 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()
J'ai déjà vérifié les erreurs simples:
- Aucune faute de frappe sur Wikipedia. J'ai vérifié les références, notamment ( 1 , 2 , 3 ).
- J'ai la bonne séquence de coefficients. Si vous comparez avec l'ordre de Wikipédia, notez que le séquencement de l'application opérateur fonctionne de droite à gauche. Ma numérotation est en accord avec Candy / Rozmus . Et si j'essaye quand même une autre commande, les résultats empirent.
Mes soupçons:
- Mauvais ordre de taille: peut-être que le schéma de 3e ordre de Ruth a des constantes implicites beaucoup plus petites, et si la taille de pas était vraiment petite, alors la méthode de 4e ordre gagnerait? Mais j'ai même essayé , et la méthode du 3ème ordre est toujours supérieure.
- Mauvais test: quelque chose de spécial dans mon test permet à la méthode de 3e ordre de Ruth de se comporter comme une méthode de plus haut niveau?