Test integratora symetrycznego trzeciego rzędu vs czwartego rzędu z dziwnym wynikiem


10

W mojej odpowiedzi na pytanie dotyczące MSE dotyczące symulacji fizyki Hamiltoniana 2D zasugerowałem użycie integratora symplektycznego wyższego rzędu .

Potem pomyślałem, że dobrym pomysłem może być wykazanie wpływu różnych kroków czasowych na globalną dokładność metod z różnymi zamówieniami. Napisałem i uruchomiłem skrypt Python / Pylab w tym celu. Do porównania wybrałem:

Dziwną rzeczą jest to, że niezależnie od wybranego przeze mnie przedziału czasu metoda trzeciego rzędu Rutha wydaje się być bardziej dokładna w moim teście niż metoda czwartego rzędu Rutha, nawet o rząd wielkości.

Moje pytanie brzmi zatem: co tutaj robię źle? Szczegóły poniżej.

Metody rozwijają swoją siłę w układach z separowalnymi hamiltonianami, tj. W tych, które można zapisać jako gdzie obejmuje wszystkie współrzędne pozycji, zawiera sprzężoną pęd, reprezentuje kinetykę energia i energia potencjalna

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

W naszym ustawieniu możemy znormalizować siły i momenty według mas, do których są przyłożone. W ten sposób siły zamieniają się w przyspieszenia, a momenty w prędkości.

Integratory symplektyczne mają specjalne (podane, stałe) współczynniki, które i . Przy tych współczynnikach przybiera postać jeden etap ewolucji systemu od czasu do czasua1,,anb1,,bntt+δt

  • Dla :i=1,,n

    1. Oblicz wektor g wszystkich przyspieszeń, biorąc pod uwagę wektor q wszystkich pozycji
    2. Zmień wektor v wszystkich prędkości o bigδt
    3. Zmiana wektora q wszystkich pozycjach przez aivδt

Mądrość leży teraz w współczynnikach. Są to

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

Do testowania wybrałem problem wartości początkowej 1D

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

Zintegrowałem IVP z powyższymi metodami w stosunku do ze skokiem wielkości z liczbą całkowitą wybraną gdzieś pomiędzy a . Biorąc pod uwagę szybkość skoku 2 , potroiłem dla tej metody. Następnie wykreśliłem otrzymane krzywe w przestrzeni fazowej i powiększyłem w gdzie krzywe powinny idealnie dotrzeć ponownie przy .t[0,2π]δt=2πNN10100N(1,0)t=2πN(1,0)t=2π

Oto wykresy i powiększenia dla i :N=12N=36

N = 12N = 12, powiększenie

N = 36N = 36, powiększenie

Dla , skok 2 z krokiem wielkości zdarza się zbliżać do domu niż ruth4 z krokiem wielkości . Dla , ruth4 wygranych ponad leap2 . Jednak ruth3 , z tym samym krokiem co ruth4 , zbliża się znacznie do domu niż oba pozostałe, we wszystkich testowanych do tej pory ustawieniach.N=122 π2π3N 2π2πNN=36

Oto skrypt 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()

Sprawdziłem już proste błędy:

  • Brak literówki w Wikipedii. Sprawdziłem referencje, w szczególności ( 1 , 2 , 3 ).
  • Mam prawidłową sekwencję współczynników. Jeśli porównasz z zamówieniami Wikipedii, zauważ, że sekwencjonowanie aplikacji operatora działa od prawej do lewej. Moja numeracja zgadza się z Candy / Rozmus . A jeśli spróbuję jeszcze raz zamówić, wyniki będą gorsze.

Moje podejrzenia:

  • Zła kolejność stopni: Może schemat Rutha trzeciego rzędu ma w jakiś sposób znacznie mniejsze implikowane stałe, a jeśli rozmiar kroku byłby naprawdę mały, to metoda czwartego rzędu wygrałaby? Ale nawet wypróbowałem , a metoda trzeciego rzędu wciąż jest lepsza.N=360
  • Błędny test: Coś specjalnego w moim teście pozwala metodzie Rutha trzeciego rzędu zachowywać się jak metoda wyższego rzędu?

Czy możesz podać liczbowe wartości błędów? Trudno powiedzieć z fabuły. Jak skalują się błędy przy zmianie ? Czy skalują się zgodnie z oczekiwaniami z zamówień metod? Zwykle wykreśla się błędy względem na wykresie dziennika, aby to sprawdzić. NNN
Kirill,

@Kirill: Pracuję nad tym. Wkrótce dokonam edycji.
ccorn,

1
Jedną z rzeczy, które mnie podejrzewają, jest wybór liniowego rhs: błędy skracania metod zwykle zależą od jakiejś wysokiej pochodnej rh, więc jeśli wszystkie wysokie pochodne rh znikną, możesz zaobserwować dziwne zachowanie zbieżności. Prawdopodobnie warto spróbować bardziej nietypowych rh.
Kirill,

Odpowiedzi:


9

Następujące Cyryla „s sugestii uruchomiony test z z listy przybliżeniu geometrycznie rosnących wartości, a dla każdego z obliczony błędu jako gdzie reprezentuje przybliżenie uzyskane przez całkowanie numeryczne. Oto wynik w dzienniku dziennika:NN

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

wprowadź opis zdjęcia tutaj

Zatem ruth3 rzeczywiście ma tę samą kolejność co ruth4 dla tego przypadku testowego i implikuje stałe tylko wielkości.41100

Ciekawy. Będę musiał zbadać dalej, być może próbując innych testów.

Nawiasem mówiąc, oto dodatki do skryptu Python dla wykresu błędów:

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()

Nie dotyczy pytania, ale czy możesz zamieścić zmiany i aktualizacje w samym pytaniu, zamiast zamieszczać osobną odpowiedź? Zachowałoby to konwencję, w której odpowiedzi powinny odpowiedzieć na pytanie.
Kirill,

1
@Kirill: To jest odpowiedź. ruth3 rzeczywiście ma tutaj wyższy porządek i mniejsze stałe. Odkryto z powodu Twojej sugestii wykonania wykresu błędów dziennika. W związku z tym odpowiedź na pytanie i zdecydowanie nie zmienię jego znaczenia po udzieleniu odpowiedzi, nawet jeśli odpowiedź jest złożona przeze mnie.
ccorn

To powiedziawszy, chętnie zaakceptuję dalszą analizę. (Pytania, na które udzielono odpowiedzi, są akceptowane automatycznie, ale chyba można to zmienić).
ccorn

2
Spojrzałem na to trochę i nie mogłem znaleźć przekonującego wyjaśnienia. Ta zbieżność ruth3 czwartego rzędu ma wiele wspólnego z warunkami początkowymi: spróbuj ustawić i spróbuj nie integrować przez pełny okres (ani półokres). Jedną rzeczą, która może się zdarzyć łatwo, jest to, że błąd obcięcia ma jakiś „zerowy” komponent, który anuluje się po zintegrowaniu z pełnym okresem. Próbowałem też aby sprawdzić, czy ma to coś wspólnego z mającym niewiele wysokich pochodnych, ale w moich testach wydaje się, że warunki początkowe i okresowość mają z tym więcej wspólnego. V ( q ) = 1 / q + log q Vp00V(q)=1/q+logqV
Kirill,

2
Jest to pokaz superkonwergencji. Takie proste problemy testowe kończą się tym problemem w wielu przypadkach. Użycie równania liniowego może dać takie zachowanie i wiele razy nieparzyste terminy serii Taylora mogą zostać anulowane, kiedy to nastąpi. Nieliniowy problem testowy bez rozwiązania analitycznego jest znacznie mniej prawdopodobny.
Chris Rackauckas,

2

Wykreślenie błędu , w pełnym przedziale, skalowane według potęgi wielkości kroku podanej w oczekiwanym porządku, daje wykresyq¨=qq(0)=1,q˙(0)=0

wprowadź opis zdjęcia tutaj

Zgodnie z oczekiwaniami wykresy rosnącej liczby pod-przedziałów coraz bardziej zbliżają się do krzywej granicznej, która jest wiodącym współczynnikiem błędu. We wszystkich wątkach z wyjątkiem jednego zbieżność ta jest widocznie szybka, prawie nie ma rozbieżności. Oznacza to, że nawet przy względnie dużych rozmiarach kroku wiodący termin błędu dominuje nad wszystkimi innymi terminami.

W metodzie Rutego trzeciego rzędu współczynnik wiodący komponentu wydaje się wynosić zero, widoczna krzywa graniczna jest bliska lub równa osi poziomej. Widoczne wykresy wyraźnie pokazują dominację terminu błędu czwartego rzędu. Skalowanie dla błędu czwartego rzędu daje wykres podobny do innych.p

Jak widać, we wszystkich 3 przypadkach współczynnik błędu rzędu wiodącego w składniku wynosi zero przy po pełnym okresie. Łącząc błędy obu komponentów dominuje zatem zachowanie komponentu , co fałszywie daje wrażenie metody czwartego rzędu na wykresie dziennika.qt=2πp

Maksymalny współczynnik w składniku można znaleźć w okolicach . Wykres dziennika powinien odzwierciedlać prawidłowe globalne zamówienia na błędy.q3π/2


To, że zniknięcie terminu błędu 3 stopnia w Ruth3p jest artefaktem prostoty równania liniowego, pokazuje nieliniowy przykładq¨=sin(q)q(0)=1.3, q˙(0)=0

wprowadź opis zdjęcia tutaj

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.