Test d'intégrateur symplectique de 3e ordre vs 4e ordre avec un résultat étrange

10

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:

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

H(q,p)=T(p)+V(q)
qpTV

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 formea1,,anb1,,bntt+δt

  • Pour :i=1,,n

    1. Calculer le vecteur de toutes les accélérations, étant donné le vecteur de toutes les positionsgq
    2. Changer le vecteur de toutes les vitesses devbigδt
    3. Changer le vecteur de toutes les positions parqaivδt

La sagesse réside maintenant dans les coefficients. Ce sont

[a1a2b1b2]=[121201](leap2)[a1a2a3b1b2b3]=[2323172434124](ruth3)[a1a2a3a4b1b2b3b4]=1223[12123212321201231](ruth4)

Pour les tests, j'ai choisi le problème de valeur initiale 1D qui a un hamiltonien séparable. Ici, sont identifiés par .

y+y=0y(0)=1y(0)=0
(y(t),y(t))=(cost,sint)
(q,v)(y,y)

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 à .t[0,2π]δt=2πNN10100N(1,0)t=2πN(1,0)t=2π

Voici des tracés et des zooms pour et :N=12N=36

N = 12N = 12, zoomé

N = 36N = 36, zoomé

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.N=122 π2π3N 2π2πNN=36

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.N=360
  • 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?
ccorn
la source
Pouvez-vous donner des valeurs numériques d'erreurs? C'est un peu difficile à dire de l'intrigue. Comment les erreurs évoluent-elles en changeant ? Est-ce qu'ils évoluent comme prévu à partir des ordres des méthodes? Habituellement, on tracerait les erreurs par rapport à sur un tracé log-log pour vérifier cela. NNN
Kirill
@Kirill: J'y travaille. Éditera bientôt.
ccorn
1
Une chose dont je me méfie est le choix d'un rh linéaire: les erreurs de troncature des méthodes dépendent généralement d'une dérivée élevée du rh, donc si toutes les dérivées élevées du rh disparaissent, vous pourriez observer un comportement de convergence étrange. Cela vaut probablement la peine d'essayer un rh plus inhabituel.
Kirill

Réponses:

9

Suite à la suggestion de Kirill , j'ai exécuté le test avec partir d'une liste de valeurs grossièrement géométriquement croissantes, et pour chaque calculé l'erreur comme où représente l'approximation obtenu par intégration numérique. Voici le résultat dans un tracé log-log:N ϵ ( N ) = ˜ z ( 2 π ) - ˜ z ( 0 ) 2NN ˜ z

ϵ(N)=z~(2π)z~(0)2wherez~(t)=(y~(t),y~(t))
z~

entrez la description de l'image ici

Donc ruth3 a en effet le même ordre que ruth4 pour ce cas de test et des constantes implicites de seulement magnitude.141100

Intéressant. Je vais devoir enquêter davantage, peut-être en essayant d'autres tests.

À propos, voici les ajouts au script Python pour le tracé d'erreur:

def int_error(qvt0, accel, qvt1, Ns, coeffs):
    e = np.empty((len(Ns),))
    for i,N in enumerate(Ns):
        t = np.linspace(qvt0[2], qvt1[2], N+1)
        q,v = symplectic_integrate(qvt0, accel, t, coeffs)
        e[i] = np.math.sqrt((q[-1]-qvt1[0])**2+(v[-1]-qvt1[1])**2)
    return e

qvt1 = (1.0, 0.0, tmax)
Ns = [12,16,20,24,32,40,48,64,80,96,128,160,192,
      256,320,384,512,640,768,1024,1280,1536,2048,2560,3072]

fig, ax = plt.subplots(1)
ax.set_xscale('log')
ax.set_xlabel(r"$N$")
ax.set_yscale('log')
ax.set_ylabel(r"$\|z(2\pi)-z(0)\|$")
ax.set_title(r"Error after 1 period vs #steps")
ax.grid(True)
e = int_error(qvt0, accel, qvt1, Ns, leap2)
ax.plot(Ns, e, label='leap2', color='black')
e = int_error(qvt0, accel, qvt1, Ns, ruth3)
ax.plot(Ns, e, label='ruth3', color='red')
e = int_error(qvt0, accel, qvt1, Ns, ruth4)
ax.plot(Ns, e, label='ruth4', color='blue')
ax.legend(loc='upper right')
fig.show()
ccorn
la source
Pas pertinent pour la question, mais pouvez-vous s'il vous plaît mettre des changements et des mises à jour dans la question elle-même, au lieu de poster en tant que réponse séparée? Cela maintiendrait la convention selon laquelle les réponses devraient répondre à la question.
Kirill
1
@Kirill: Il est une réponse. ruth3 a en effet ici des constantes d'ordre supérieur et moindre. Découvert en raison de votre suggestion de créer un tracé d'erreur log-log. Il est donc répondu à la question et je ne changerai certainement pas le point d'une question une fois qu'elle aura été répondue, même si la réponse a été composée par moi.
ccorn
Cela dit, je serais heureux d'accepter une analyse plus approfondie. (Les réponses aux questions sont acceptées automatiquement, mais on peut changer cela, je suppose.)
ccorn
2
Je l'ai regardé un peu et je n'ai pas pu trouver d'explication convaincante. Cette convergence de 4e ordre de ruth3 a beaucoup à voir avec les conditions initiales: essayez de définir et essayez de ne pas intégrer pendant une période complète (ni demi-période). Une chose qui peut se produire facilement est que l'erreur de troncature a un composant "zéro-moyenne" qui s'annule lorsque vous intégrez à une période complète. J'ai également essayé pour vérifier si cela a quelque chose à voir avec ayant peu de dérivés élevés, mais dans mes tests, il semble que les conditions initiales et la périodicité ont plus à voir avec cela. V ( q ) = 1 / q + log q Vp00V(q)=1/q+logqV
Kirill
2
Il s'agit d'un affichage de superconvergence. Des problèmes de test simples comme celui-ci finissent par avoir ce problème dans de nombreux cas. L'utilisation d'une équation linéaire peut donner ce comportement, et plusieurs fois les termes impairs d'une série de Taylor peuvent s'annuler lorsque cela se produit. Un problème de test non linéaire sans solution analytique est beaucoup moins susceptible de se produire.
Chris Rackauckas
2

Tracer l'erreur de , sur l'intervalle complet, mis à l'échelle par la puissance de la taille de pas donnée par l'ordre attendu, donne les tracésq¨=qq(0)=1,q˙(0)=0

entrez la description de l'image ici

Comme prévu, les graphiques pour l'augmentation du nombre de sous-intervalles se rapprochent de plus en plus d'une courbe limite qui est le coefficient d'erreur principal. Dans toutes les parcelles sauf une, cette convergence est visiblement rapide, il n'y a presque pas de divergence. Cela signifie que même pour des tailles de pas relativement grandes, le terme d'erreur dominant domine tous les autres termes.

Dans la méthode Ruth du 3ème ordre, le coefficient de tête de la composante semble être nul, la courbe limite visible est proche ou égale à l'axe horizontal. Les graphiques visibles montrent clairement la dominance du terme d'erreur du 4ème ordre. La mise à l'échelle pour une erreur de 4e ordre donne un tracé similaire aux autres.p

Comme on peut le voir, dans les 3 cas, le coefficient d'erreur de l'ordre principal dans la composante est nul à après une période complète. En combinant les erreurs des deux composantes, le comportement de la composante domine donc, donnant faussement l'impression d'une méthode de 4ème ordre dans le graphique du loglog.qt=2πp

Un coefficient maximal dans la composante peut être trouvé autour de . Le tracé du journal devrait refléter les ordres d'erreur globale corrects.q3π/2


Le fait que la disparition du terme d'erreur du 3ème degré dans Ruth3p soit un artefact de la simplicité de l'équation linéaire montre l'exemple non linéaire , avec les tracés correspondantsq¨=sin(q)q(0)=1.3, q˙(0)=0

entrez la description de l'image ici

Lutz Lehmann
la source