Forum der Vereinigung der Sternfreunde

Forum of the German Amateur Astronomy Association
Aktuelle Zeit: 12. Januar 2026, 04:00:19 AM

Alle Zeiten sind UTC+02:00




Ein neues Thema erstellen  Auf das Thema antworten  [ 1 Beitrag ] 
Autor Nachricht
BeitragVerfasst: 20. Januar 2025, 12:47:30 PM 
Offline
Meister
Benutzeravatar

Registriert: 20. Januar 2013, 20:03:54 PM
Beiträge: 1978
Wohnort: Leipzig
Liebe Sternfreunde, das Heft 92 sollte demnächst in eurem Kasten liegen. Ich habe diesmal ein stark astrophysikalisch durchdrungenes Thema als Schwerpunkt. Ich fand es sehr erkenntnisreich, die Simulation von Sternhaufen slebst nachzurechnen. Hier an diese Mail klebe ich das Python-Programm dran. Ihr braucht das Programm plot.py dazu, es muss im selben Verzeichnis liegen

Die Rechenzeiten sind lang, manches lief bei mir mehrere Tage.
Dagegen gibt es zwei "Medikamente":
1) Ich habe denselben Algorithmus in C++ vorliegen. Den müsst ihr aber auf eurem Computer übersetzen, Gnu-C++ geht. Wer das haben möchte: Mich bitte anschreiben.
2) Das sehr weit entwickelte Programm nbody6 von Sverre Aarseth. Ich kann den leicht modifizierten Fortran-Code weggeben (einen Fehler gefunden und die Ausgabe angepasst) oder eine ausführbare Datei für Windows. Gnu-Fortran genügt zum übersetzen, zum Benutzen braucht ihr sicher Unterstützung von mir.

Sverre hat sein ganzes Berufsleben daran gearbeitet und war ein Vorreiter freier Software. Er ist übrigens vor wenigen Tagen verstorben. Ich hatte zuletzt 2022 zuletzt Kontakt zu ihm. Seinerzeit fiel es ihm schon schwer, am Bildschirm etwas zu lesen.

~

Das PythonProgramm findet sich auch auf unserer Internetseite.

Code:
# nbodyCluster (ohne Doppelsternbehandlung): Analyse der Entwicklung von Sternhaufen
from math import *
from random import *
from plot import *
from sys import *

G = 1     # Gravitationskonstante ist 1 gesetzt (einheitenfreies rechnen)
N = 100   # Anzahl der Körper
Q = 1     # Anfangsradius R0
M = 1     # Gesamtmasse
o = 1000  # Anzahl Ausgabewerte gesamt.  
J = 0.03  # maximaler Ruck, J<0.03
g = 1     # Genauigkeitssteuerung an/aus
S = 30    # t* bis Simulationsende
l = 3.0   # Limit für Entweicher. 3 ist in Ordnung
L = l
xNext = 3 # der drittnächste Stern für die Dichteberechnung

E=100    # Abbruch bei xx % Entweichern
rP = 0.05 / (N ** 0.333) # Plummer-Radius, spart Rechenzeit und erschwert das Entstehen von Doppelsternen
d = 0.1 * sqrt(1/N)      # deltaT vor der ersten Steuerung. (#8-22)
grafik=1                 # nur Text oder auch Grafik? 0/1

r = [[0.0 for i in range(3)] for j in range(N)]
v = [[0.0 for i in range(3)] for j in range(N)]
w = [[0.0 for i in range(3)] for j in range(N)] # die Hilfsgeschwindigkeit v05
a = [[0 for i in range(3)] for j in range(N)]
b = [[0.0 for i in range(3)] for j in range(N)]
m = [0.0 for i in range(N)]
R = [0.0 for i in range(N)]



def sq(x):
    return x * x


def baryzentrischR(N): 
    x = 0
    y = 0
    z = 0
    LL = 0
    for i in range(N): # Schwerpunkt berechnen ...
        x+=m[i] * r[i][0]
        y+=m[i] * r[i][1]
        z+=m[i] * r[i][2]
        LL+=m[i]
    for i in range(N): # ...  korrigieren
        r[i][0]-=x / LL
        r[i][1]-=y / LL
        r[i][2]-=z / LL

def baryzentrischV(N): 
    x = 0
    y = 0
    z = 0
    for i in range(N): # mittl.  Geschwindigkeit ber...
        x+=v[i][0]
        y+=v[i][1]
        z+=v[i][2]
    for i in range(N): # ...  korrigieren
        v[i][0]-=x / N
        v[i][1]-=y / N
        v[i][2]-=z / N



def wPot(N): 
    P = 0 
    for i in range(N):
        for j in range(i + 1,N):
            R = 0
            for k in range(3):
                R = R + sq(r[i][k] - r[j][k])
            R = sqrt(R)
            P = P + m[i] * m[j] / R
    P = G * P
    return (P)

def wKin(N): 
    K = 0
    for i in range(N):
        V = sq(v[i][0]) + sq(v[i][1]) + sq(v[i][2])
        K+=m[i] / 2 * V
    return K

def beschleunigung(): 
    global d
    global D
    global c
    for p in range(N):    # alle Beschleunigungen löschen / kopieren
        for k in range(3):
            b[p][k] = a[p][k]
            a[p][k] = 0
    B = 0
    for p in range(N): # alle Körper
        for q in range(p + 1, N): # gegen alle anderen Körper
            R = sqrt(sq(r[p][0] - r[q][0]) + sq(r[p][1] - r[q][1]) + sq(r[p][2] - r[q][2]))
            # E = R * R * R # E ist die umgekehrte 3, also R3
            E = R * (R * R + rP * rP) # mit Plummer-Radius
            for k in range(3):
                A = G * (r[q][k] - r[p][k]) / E
                a[p][k]+=m[q] * A
                a[q][k]-=m[p] * A
        # beide Beschleunigungen existieren jetzt, größten Ruck ber.
        j = sqrt(sq(a[p][0] - b[p][0]) + sq(a[p][1] - b[p][1]) + sq(a[p][2] - b[p][2]))
        A = sqrt(sq(a[p][0]) + sq(a[p][1]) + sq(a[p][2]))
        if (j / A > B): # größten Ruck in B aufheben
            B = j / A
    # neuen Zeitschritt ausrechnen
    D = d
    if B > 0:
        D = J / B * d # Vorschlag für den neuen Zeitschritt

# nach Hermite-Verfahren
def  startwerte():
    # seed(31) # seed / random nur für Tests
    A = 6.0 / 5.0 # für Radius
    for i in range(N):
        R = A * ( random()**0.33333333)
        cos_theta = 2.0 * random() - 1.0
        sin_theta = sqrt(1 - (cos_theta*cos_theta))
        phi = 2 * pi * random()
        r[i][0] = R * sin_theta * cos(phi)
        r[i][1] = R * sin_theta * sin(phi)
        r[i][2] = R * cos_theta
    A = 5.0 / 6.0 # für Geschwindigkeit
    for i in range(N):
        V = A * (random()**0.333333333)
        cos_theta = 2.0 * random() - 1
        sin_theta = sqrt(1 - (cos_theta*cos_theta))
        phi = 2 * pi * random()
        v[i][0] = V * sin_theta * cos(phi)
        v[i][1] = V * sin_theta * sin(phi)
        v[i][2] = V * cos_theta
    for i in range(N):
        m[i] = 1.0 / N
    baryzentrischR(N)
    # virialisieren
    K = wKin(N)
    P = wPot(N)
    c = sqrt(2 * K / P)
    for i in range(N):
        for k in range(3):
            v[i][k]/=c # /=c: virialisiert 
            v[i][k] = 0 # =0:kalter Kollaps. Auskommentieren für virialisierten Start
    baryzentrischV(N)
    beschleunigung() # die erste Beschleunigung gleich hier
    return c


def leapfrog1(): 
    # eine Hilfsgeschwindigkeit in Intervallmitte wird benötigt
    for i in range(N):
        for k in range(3):
            w[i][k] = v[i][k] + a[i][k] * d / 2  # v05 = v + a * dt / 2
    # der neue Ort nimmt die mittlere Geschwindigkeit 
    # Damit ist es ein quadratisches Verfahren
    for i in range(N):
        for k in range(3):
            r[i][k] = r[i][k] + w[i][k] * d   # s = s + v05 * dt
    # die Geschwindigkeit muss korrigiert werden
    beschleunigung()    
    for i in range(N):
        for k in range(3):
            v[i][k] = w[i][k] + a[i][k] * d / 2  # v=v05+a*dt/2

def leapfrog():
    global t
    global d
    while t <= T:
        leapfrog1()
        t = t + d
        if (g > 0.1): # neuer Zeitschritt nur, falls das Genauigkeitsflag gesetzt ist
            d = D


def abstand(i, j):
    return sqrt(sq(r[i][0] - r[j][0]) + sq(r[i][1] - r[j][1]) + sq(r[i][2] - r[j][2]))


def volumen(r):
    return 1.333 * pi * r * r * r


def rC(N):
    Next=[0.0 for i in range(xNext)]
    rho = [[0.0 for i in range(2)] for j in range(N)]
    for i in range(N): # Dichte um jeden Stern    
        for j in range (xNext):
            Next[j] = 7e77
        for j in range (N): # gegen jeden anderen Stern
            dist = abstand(i, j)
            for k in range (xNext):
                if (i != j) and (dist < Next[k]):
                    for l in range(xNext - 1, k, -1):
                        Next[l] = Next[l - 1] # ein Element Platz schaffen
                    Next[k] = dist
                    break
        rho[i][0] = R[i]
        rho[i][1] = (xNext - 1) / volumen(Next[xNext-1])
    # zentrale Dichte: die inneren 2%. das ist zweckmäßig bis N~500. Darüber: verkleinern.
    anzC = int(0.02 * N + 0.5)
    if (anzC < 2):
       anzC = 2
    rhoC = 0.0
    for i in range(anzC):
        rhoC += rho[i][1]
    rhoC /= anzC
    # Radius der viertel zentralen Dichte zurückmelden. Wird durch Doppelsterne verfälscht, hier nicht behoben.
    radC=0
    anzC=0
    for i in range(N):
        Rho = rho[i][1]
        if (Rho < 0.25 * rhoC):
            radC = rho[i][0]
            anzC = i + 1
            break
    return radC, anzC, rhoC

# Doppelsterne: näher als 0.03, hängt nicht von N ab!
def DS(N):
    dslimit = 0.03 
    ds = 0
    for i in range(N): # Dichte jeden Stern prüfen
        for j in range(i+1,N): # gegen jeden anderen Stern
            dist = abstand(i, j)
            if (dist < dslimit):
               ds=ds+1
    return ds/2 # jeder Stern wurde 2x berücksichtigt

def rH(n, t):
    return R[int((N - n) / 2)] # nur valide für identische Massen aller Körper. Die Entweicher abziehen.

def ausgabe(): 
    # Grafik
    global L
    n=0 # Anzahl Entweicher
    for i in range(N):
        if (grafik>0): Plot(r[i][0] / Q, r[i][1] / Q, 4, "black")
        R[i] = sqrt(sq(r[i][0]) + sq(r[i][1]) + sq(r[i][2]))
        if (R[i]>L): # L: Limit für Entweicher
           n=n+1
    R.sort()
    radC, anzC, rhoC=rC(N)
    radH=rH(n, t)
    L = l * radH # Grenze für Entweicher aktualisieren  
    K = wKin(N)
    P = wPot(N)
    ds=DS(N)
    #     1  2     3  4    5   6    7     8   9     
    #     t* N     rH wKin wPot rC  nC   dbl  pC
    print(t, N-n, radH, K, P, radC, anzC, ds, rhoC)
    abbruch=0
    if (n>(E/100.0)*N-0.5):
        abbruch=1
    return abbruch # Abbruch durch Entweicher


# Hauptprogramm
c = startwerte() 

# Koordinatensystem einrichten
#                       x0 x1 xScale y0 y1 yScale
if (grafik>0): initKoor(-3 ,3 ,0.5, -2.5,2.5,0.5) 
s = S / o # Zeitschritt für Mehrfach-Leapfrog
t = 0
clrgraf=0
while t < S:
    T = t + s # Tend für leapfrog
    if (T > S): T = S
    clrgraf=clrgraf+s
    if (clrgraf>1):
        if (grafik>0): initKoor(-3 ,3 ,0.5, -2.5,2.5,0.5) 
        clrgraf=0
    abbruch=ausgabe()
    if (abbruch>0):
        t=S+1
    leapfrog()
    if (grafik>0): update() 
if (grafik>0): name = input("Enter!") # wg. Aufruf von Konsole und grep/plot




Dateianhänge:
Abb2.jpg
Abb2.jpg [ 516.27 KiB | 1330 mal betrachtet ]
2_3-100.jpg
2_3-100.jpg [ 65.58 KiB | 1330 mal betrachtet ]
abb2v4MitDS.jpg
abb2v4MitDS.jpg [ 127.7 KiB | 1330 mal betrachtet ]

_________________
Uwe Pilz, Fachgruppen Kometen und Astrophysik/Algorithmen.
Oft benutzte Instrumente: Fujinon 16x70 FMT-SX-2, TMB Apo 105/650, Skywatcher Evostar 120/900 ED, Ninja Dobson 320/1440, Smartscope Dwarf-3
Nach oben
   
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen  Auf das Thema antworten  [ 1 Beitrag ] 

Alle Zeiten sind UTC+02:00


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
Powered by phpBB® Forum Software © phpBB Limited
Deutsche Übersetzung durch phpBB.de