Files
2024-06-19 15:45:57 +02:00

165 lines
5.8 KiB
Python

"""
* COSMIC : Cluster Orbital SysteM Integration Code
* Version 2 - 2024-02-27
@ Yaël Moussouni
@ Unistra, P&E, MSc1-MoFP
@ Observatory of Strasbourg (Intern)
"""
import numpy as np
import amuse.units.units as u
import datetime
from amuse.units import nbody_system
from amuse.ic.kingmodel import new_king_model
from amuse.ic.salpeter import new_salpeter_mass_distribution
from amuse.datamodel.particles import Channels
from amuse.community.ph4.interface import Ph4
from amuse.community.seba.interface import SeBa
from amuse.couple.bridge import Bridge
# * Parameters
N_part = 10 # Number of particle
N_iter = 30 # Number of iteration
dt = 1|u.Myr # Time increment
R0 = 1|u.parsec # Radius of the system
W0 = 9 # King parameter
z = 0.02 # Metallicity
# * Variables
date = datetime.datetime.now()
date = "{:04d}-{:02d}-{:02d}_{:02d}h{:02d}".format(date.year, date.month, date.day, date.hour, date.minute)
directory = "./output/"
filename_cluster = "{}_cluster.csv".format(date)
filename_stars = "{}_stars.csv".format(date)
# * Function
def get_total_momentum(M, X, V):
"""
Compute the total momentum of particles with mass M, positions X and velocities V.
"""
l = 0
for j in range(len(X)):
m = M[j].value_in(u.MSun)
x = X[j].value_in(u.pc)
v = V[j].value_in(u.pc/u.Myr)
l += m*np.cross(x,v)
return np.sqrt(np.sum(l**2))|(u.pc**2 * u.MSun / u.Myr)
# * Initialization
def create_cluster(N:int, R=1|u.pc, W=9):
"""
Create cluster of N stars of radius R (default: 1 pc) following King model of parameter W (default: 9).
"""
print("\033[94m"+"Info: Simulation with "+"\033[0m"+"{}".format(N)+"\033[94m"+" stars"+"\033[0m")
M_stars = new_salpeter_mass_distribution(N)
converter = nbody_system.nbody_to_si(M_stars.sum(), R)
stars = new_king_model(N, W, converter)
stars.mass = M_stars
stars.zams_mass = M_stars
return stars, converter
# * Evolution
def stellar_gravity_evolution(stars, converter, t_max=16|u.Myr, dt=1|u.Myr, out_dt=1|u.Myr):
"""
Evolve a model with both gravity and stellar evolution. dt is the simulation time step, while out_dt is the delay between printing in file.
"""
print("\033[94m"+"Info: Simulation duration of "+"\033[0m"+"{:.2f} Myr".format(t_max.value_in(u.Myr)))
init_files()
gravity = Ph4(converter) # gravity model
stellar = SeBa() # stellar model
bridge = Bridge() # bridge between models
# TODO gravity.initialize_code()
gravity.particles.add_particles(stars)
stellar.particles.add_particles(stars)
stellar.set_metallicity(z)
stellar.commit_particles()
stellar.update_particles(stars) # TODO pourquoi ?
bridge.add_system(gravity)
bridge.add_system(stellar)
bridge.synchronize_model()
bridge.channels.add_channel(stellar.particles.new_channel_to(gravity.particles, attributes=["mass", "radius"]))
# Sync the mass and radius between the two models
out_channel = Channels()
out_channel.add_channel(stellar.particles.new_channel_to(stars))
out_channel.add_channel(gravity.particles.new_channel_to(stars))
bridge.timestep = dt # TODO timestep dynamique
print(gravity.get_initial_timestep_median()) # TODO ????
i = 0
t = 0 | u.Myr
E0 = gravity.get_total_energy()
L0 = get_total_momentum(stars.mass, stars.position, stars.velocity)
while t <= t_max:
print("\033[36m"+"t: "+"\033[0m"+"{:02.2f} Myr/{:02.2f} Myr".format(t.value_in(u.Myr),t_max.value_in(u.Myr)))
bridge.evolve_model(t)
out_channel.copy()
E = gravity.get_total_energy()
L = get_total_momentum(stars.mass, stars.position, stars.velocity)
write_files(stars, i, t, E, E0, L, L0)
i += 1
t += out_dt
print("\033[36m"+"t: "+"\033[0m"+"{:02.2f} Myr/{:02.2f} Myr".format(t_max.value_in(u.Myr),t_max.value_in(u.Myr)))
print("\033[36m"+"Simulation completed"+"\033[0m")
return 0
# * Files initialization and write
def init_files():
file = open(directory+filename_cluster, "w")
file.write("#i (time), t [Myr], E [pc2 MSun Myr-2], (E-E0)/E0, L [pc2 MSun Myr-1], (L-L0)/L0\n")
file.close()
file = open(directory+filename_stars, "w")
file.write("#i (time), j (star), m [MSun], x [pc], y [pc], z [pc], vx [km s-1], vy [km s-1], vz [km s-1], L [LSun], R [RSun], T [K]\n")
file.close()
print("\033[94m"+"Info: Created two output files with date " + "\033[0m" + date.replace("h", ":").replace("_", " "))
return 0
def write_files(stars, i, t, E, E0, L, L0):
file = open(directory+filename_cluster, "a")
file.write("{:d}, ".format(i))
file.write("{:+e}, ".format(t.value_in(u.Myr)))
file.write("{:+e}, ".format(E.value_in(u.pc**2 * u.MSun * u.Myr**-2)))
file.write("{:+e}, ".format((E-E0)/E0))
file.write("{:+e}, ".format(L.value_in(u.pc**2 * u.MSun * u.Myr**-1)))
file.write("{:+e}\n".format((L-L0)/L0))
file.close()
file = open(directory+filename_stars, "a")
for j in range(N_part):
file.write("{:d}, ".format(i))
file.write("{:d}, ".format(j))
file.write("{:+e}, ".format(stars.mass[j].value_in(u.MSun)))
file.write("{:+e}, ".format(stars.position[j,0].value_in(u.pc)))
file.write("{:+e}, ".format(stars.position[j,1].value_in(u.pc)))
file.write("{:+e}, ".format(stars.position[j,2].value_in(u.pc)))
file.write("{:+e}, ".format(stars.velocity[j,0].value_in(u.km * u.s**-1)))
file.write("{:+e}, ".format(stars.velocity[j,1].value_in(u.km * u.s**-1)))
file.write("{:+e}, ".format(stars.velocity[j,2].value_in(u.km * u.s**-1)))
file.write("{:+e}, ".format(stars.luminosity[j].value_in(u.LSun)))
file.write("{:+e}, ".format(stars.radius[j].value_in(u.RSun)))
file.write("{:+e}\n".format(stars.temperature[j].value_in(u.K)))
file.close()
return 0
# * Main
cluster, nbody_converter = create_cluster(N_part, R0, W0)
stellar_gravity_evolution(cluster, nbody_converter, N_iter*dt, dt, dt)