1
0
Fork 0
mirror of https://github.com/Findus23/rebound-collisions.git synced 2024-09-19 15:53:48 +02:00

better merging, loading of saves and unique hashes

This commit is contained in:
Lukas Winkler 2021-02-11 21:14:29 +01:00
parent 187dda2803
commit 452327c06d
Signed by: lukas
GPG key ID: 54DE4D798D244853
5 changed files with 56 additions and 45 deletions

2
.gitignore vendored
View file

@ -14,3 +14,5 @@ data/
tmp/ tmp/
notes.md notes.md
poc* poc*
plots/
*.md

View file

@ -71,6 +71,7 @@ class Meta:
walltime: int = None # seconds walltime: int = None # seconds
cputime: int = None # seconds cputime: int = None # seconds
current_time: float = None current_time: float = None
hash_counter: int = 0
git_hash: str = None git_hash: str = None
perfect_merging: bool = None perfect_merging: bool = None

View file

@ -6,7 +6,7 @@ from typing import Tuple
import numpy as np import numpy as np
from numpy import linalg, sqrt from numpy import linalg, sqrt
from rebound import Simulation, Particle, reb_simulation_integrator_mercurius from rebound import Simulation, Particle
from rebound.simulation import POINTER_REB_SIM, reb_collision from rebound.simulation import POINTER_REB_SIM, reb_collision
from scipy.constants import astronomical_unit, G from scipy.constants import astronomical_unit, G
@ -81,50 +81,52 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
print("--------------") print("--------------")
print("colliding") print("colliding")
sim: Simulation = sim_p.contents sim: Simulation = sim_p.contents
print("current time step", sim.dt, ) print("current time step", sim.dt)
print("mode", sim.ri_mercurius.mode) print("mode", sim.ri_mercurius.mode)
# the assignment to cp1 or cp2 is mostly random # the assignment to cp1 or cp2 seems to be random
# (cp1 is the one with a lower index in sim.particles)
# naming them projectile or target is therefore also arbitrary
# also look at a copy instead of the original particles # also look at a copy instead of the original particles
# to avoid issues after they have been modified # to avoid issues after they have been modified
cp1: Particle = sim.particles[collision.p1].copy() # projectile cp1: Particle = sim.particles[collision.p1].copy()
cp2: Particle = sim.particles[collision.p2].copy() # target cp2: Particle = sim.particles[collision.p2].copy()
# just calling the more massive one the main particle to keep its type/name # just calling the more massive one the target to keep its type/name
# Sun<->Protoplanet -> Sun # Sun<->Protoplanet -> Sun
# and to keep collsions mostly reproducable
if cp1.m > cp2.m: if cp1.m > cp2.m:
main_particle_id = collision.p1 target = cp1
main_particle = cp1 projectile = cp2
else: # also when masses are the same
target = cp2
projectile = cp1
if collision.p1 > collision.p2:
lower_index_particle = cp2
else: else:
main_particle_id = collision.p2 lower_index_particle = cp1
main_particle = cp2
print(f"colliding {ed.pd(cp1).type} with {ed.pd(cp2).type}") print(f"colliding {ed.pd(target).type} with {ed.pd(projectile).type}")
projectile_wmf = ed.pd(cp1).water_mass_fraction projectile_wmf = ed.pd(projectile).water_mass_fraction
target_wmf = ed.pd(cp2).water_mass_fraction target_wmf = ed.pd(target).water_mass_fraction
# get the velocities, velocity differences and unit vector as numpy arrays # get the velocities, velocity differences and unit vector as numpy arrays
# all units are in sytem units (so AU/year) # all units are in sytem units (so AU/year)
v1 = np.array(cp1.vxyz) v1 = np.array(target.vxyz)
v2 = np.array(cp2.vxyz) v2 = np.array(projectile.vxyz)
r1 = np.array(cp1.xyz) r1 = np.array(target.xyz)
r2 = np.array(cp2.xyz) r2 = np.array(projectile.xyz)
vdiff = v2 - v1 vdiff = v2 - v1
rdiff = r2 - r1 rdiff = r2 - r1
vdiff_n = linalg.norm(vdiff) vdiff_n = linalg.norm(vdiff)
rdiff_n = linalg.norm(rdiff) rdiff_n = linalg.norm(rdiff)
print("dt", sim.dt) print("dt", sim.dt)
merc: reb_simulation_integrator_mercurius = sim.ri_mercurius
print("current mode", "ias15" if merc.mode else "whfast")
# during a collision ias15 should always be used, otherwise something weird has happend # during a collision ias15 should always be used, otherwise something weird has happend
assert merc.mode == 1 assert sim.ri_mercurius.mode == 1
print("rdiff", rdiff) print("rdiff", rdiff)
print("vdiff", vdiff) print("vdiff", vdiff)
print("sum_radii", cp1.r + cp2.r) print("sum_radii", target.r + projectile.r)
print("rdiff_n", rdiff_n) print("rdiff_n", rdiff_n)
print("vdiff_n", vdiff_n) print("vdiff_n", vdiff_n)
ang = float(np.degrees(np.arccos(np.dot(rdiff, vdiff) / (rdiff_n * vdiff_n)))) ang = float(np.degrees(np.arccos(np.dot(rdiff, vdiff) / (rdiff_n * vdiff_n))))
@ -134,11 +136,10 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
print("angle_deg", ang) print("angle_deg", ang)
print() print()
# get mass fraction # get mass fraction
# if it is >1 it will be inverted during interpolation gamma = projectile.m / target.m
gamma = cp1.m / cp2.m
# calculate mutual escape velocity (for norming the velocities in the interpolation) in SI units # calculate mutual escape velocity (for norming the velocities in the interpolation) in SI units
escape_velocity = sqrt(2 * G * (cp1.m + cp2.m) / ((cp1.r + cp2.r) * astronomical_unit)) escape_velocity = sqrt(2 * G * (target.m + projectile.m) / ((target.r + projectile.r) * astronomical_unit))
print("interpolating") print("interpolating")
@ -150,7 +151,7 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
velocity_original=vdiff_n, velocity_original=vdiff_n,
escape_velocity=escape_velocity, escape_velocity=escape_velocity,
gamma=gamma, gamma=gamma,
projectile_mass=cp1.m, projectile_mass=projectile.m,
target_water_fraction=target_wmf, target_water_fraction=target_wmf,
projectile_water_fraction=projectile_wmf, projectile_water_fraction=projectile_wmf,
) )
@ -160,14 +161,14 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
print(water_ret, stone_ret) print(water_ret, stone_ret)
meta.collision_velocities = (v1.tolist(), v2.tolist()) meta.collision_velocities = (v1.tolist(), v2.tolist())
meta.collision_positions = (cp1.xyz, cp2.xyz) meta.collision_positions = (target.xyz, projectile.xyz)
meta.collision_radii = (cp1.r, cp2.r) meta.collision_radii = (target.r, projectile.r)
hash = unique_hash() # hash for newly created particle hash = unique_hash(ed) # hash for newly created particle
# handle loss of water and core mass # handle loss of water and core mass
water_mass = cp1.m * projectile_wmf + cp2.m * target_wmf water_mass = target.m * target_wmf + projectile.m * projectile_wmf
stone_mass = cp1.m + cp2.m - water_mass stone_mass = target.m + projectile.m - water_mass
water_mass *= water_ret water_mass *= water_ret
stone_mass *= stone_ret stone_mass *= stone_ret
@ -176,14 +177,14 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
final_wmf = water_mass / total_mass final_wmf = water_mass / total_mass
print(final_wmf) print(final_wmf)
# create new object preserving momentum # create new object preserving momentum
merged_planet = (cp1 * cp1.m + cp2 * cp2.m) / total_mass merged_planet = (target * target.m + projectile * projectile.m) / total_mass
merged_planet.m = total_mass merged_planet.m = total_mass
merged_planet.hash = hash merged_planet.hash = hash
merged_planet.r = radius(merged_planet.m, final_wmf) / astronomical_unit merged_planet.r = radius(merged_planet.m, final_wmf) / astronomical_unit
ed.pdata[hash.value] = ParticleData( ed.pdata[hash.value] = ParticleData(
water_mass_fraction=final_wmf, water_mass_fraction=final_wmf,
type=ed.pd(main_particle).type, type=ed.pd(target).type,
total_mass=total_mass total_mass=total_mass
) )
@ -194,9 +195,9 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
meta.time = sim.t meta.time = sim.t
pprint(meta) pprint(meta)
ed.tree.add(cp1, cp2, merged_planet, meta) ed.tree.add(target, projectile, merged_planet, meta)
sim.particles[main_particle_id] = merged_planet sim.particles[lower_index_particle.index] = merged_planet
sim.move_to_com() sim.move_to_com()
sim.integrator_synchronize() sim.integrator_synchronize()
@ -209,8 +210,9 @@ def merge_particles(sim_p: POINTER_REB_SIM, collision: reb_collision, ed: ExtraD
# A return value of 0 indicates that both particles remain in the simulation. # A return value of 0 indicates that both particles remain in the simulation.
# A return value of 1 (2) indicates that particle 1 (2) should be removed from the simulation. # A return value of 1 (2) indicates that particle 1 (2) should be removed from the simulation.
# A return value of 3 indicates that both particles should be removed from the simulation. # A return value of 3 indicates that both particles should be removed from the simulation.
# always keep lower index particle and delete other one
if main_particle_id == collision.p1: # this keeps the N_active working
if lower_index_particle.index == collision.p1:
return 2 return 2
else: else:
return 1 return 1

View file

@ -21,7 +21,7 @@ solar_radius = 6.957e8
solar_mass = 1.9885e+30 solar_mass = 1.9885e+30
def unique_hash() -> c_uint32: def random_hash() -> c_uint32:
""" """
returns a (hopefully) unique 32 bit integer to be used as a particle hash returns a (hopefully) unique 32 bit integer to be used as a particle hash
@ -30,6 +30,11 @@ def unique_hash() -> c_uint32:
return c_uint32(randint(0, 2 ** 32 - 1)) return c_uint32(randint(0, 2 ** 32 - 1))
def unique_hash(ed: ExtraData) -> c_uint32:
ed.meta.hash_counter += 1
return c_uint32(ed.meta.hash_counter)
def innermost_period(sim: Simulation) -> float: def innermost_period(sim: Simulation) -> float:
""" """
returns the orbital period in years of the innerpost object returns the orbital period in years of the innerpost object
@ -38,11 +43,11 @@ def innermost_period(sim: Simulation) -> float:
minp = None minp = None
mina = float("inf") mina = float("inf")
for p in sim.particles[1:]: for p in sim.particles[1:]:
if p.a < mina: if abs(p.a) < mina:
mina = p.a mina = abs(p.a)
minp = p minp = p
orb: Orbit = minp.orbit orb: Orbit = minp.orbit
return orb.P return abs(orb.P)
def third_kepler_law(orbital_period: float): def third_kepler_law(orbital_period: float):

View file

@ -76,7 +76,7 @@ def main(fn: Path, testrun=False):
if line.startswith("#") or line.startswith("ERROR") or line == "\n" or not line: if line.startswith("#") or line.startswith("ERROR") or line == "\n" or not line:
continue continue
columns = list(map(float, line.split())) columns = list(map(float, line.split()))
hash = unique_hash() hash = unique_hash(extradata)
if len(columns) > 7: if len(columns) > 7:
# print(columns[7:]) # print(columns[7:])
cmf, mmf, wmf = columns[7:] cmf, mmf, wmf = columns[7:]
@ -141,8 +141,9 @@ def main(fn: Path, testrun=False):
extradata = ExtraData.load(fn) extradata = ExtraData.load(fn)
tmax = extradata.meta.tmax tmax = extradata.meta.tmax
per_savestep = extradata.meta.per_savestep per_savestep = extradata.meta.per_savestep
t = extradata.meta.current_time sim = sa[-1]
sim = sa.getSimulation(t=t - per_savestep) t = round(sim.t + per_savestep)
print(f"continuing from {t}")
sim.move_to_com() sim.move_to_com()
sim.ri_mercurius.recalculate_coordinates_this_timestep = 1 sim.ri_mercurius.recalculate_coordinates_this_timestep = 1
sim.integrator_synchronize() sim.integrator_synchronize()