2019-07-06 13:24:48 +02:00
|
|
|
import json
|
2021-10-12 15:45:43 +02:00
|
|
|
from pathlib import Path
|
2021-03-29 15:02:46 +02:00
|
|
|
from typing import Optional
|
2019-07-06 13:24:48 +02:00
|
|
|
|
2021-10-12 15:45:43 +02:00
|
|
|
import yaml
|
|
|
|
|
2019-07-06 13:24:48 +02:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
class Simulation:
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.runid = None # type:int
|
|
|
|
self.vcode = None
|
|
|
|
self.alphacode = None
|
|
|
|
self.mcode = None
|
|
|
|
self.gammacode = None
|
|
|
|
self.wtcode = None
|
|
|
|
self.wpcode = None
|
2019-07-06 13:24:48 +02:00
|
|
|
self.type = None # simulation set
|
2019-02-12 18:56:05 +01:00
|
|
|
self.v = None # v/v_esc
|
|
|
|
self.alpha = None # impact angle
|
|
|
|
self.total_mass = None # m
|
|
|
|
self.projectile_mass = None # mp
|
|
|
|
self.target_mass = None # mt
|
|
|
|
self.projectile_water_fraction = None # wp
|
2021-03-08 13:25:11 +01:00
|
|
|
self.projectile_core_fraction = None
|
2019-02-12 18:56:05 +01:00
|
|
|
self.target_water_fraction = None # wt
|
2021-03-08 13:25:11 +01:00
|
|
|
self.target_core_fraction = None
|
2019-02-12 18:56:05 +01:00
|
|
|
self.largest_aggregate_mass = None # mS1
|
|
|
|
self.largest_aggregate_water_fraction = None # wmfS1
|
2021-03-08 13:25:11 +01:00
|
|
|
self.largest_aggregate_core_fraction = None
|
2019-02-12 18:56:05 +01:00
|
|
|
self.second_largest_aggregate_mass = None # mS2
|
|
|
|
self.second_largest_aggregate_water_fraction = None # wmfS2
|
2021-03-08 13:25:11 +01:00
|
|
|
self.second_largest_aggregate_core_fraction = None
|
2019-02-12 18:56:05 +01:00
|
|
|
self.rel_velocity = None # vrel
|
|
|
|
self.rel_velocity_per_esc_velocity = None # vrel_over_vesc
|
2020-11-30 12:58:50 +01:00
|
|
|
self.desired_N = None
|
|
|
|
self.actual_N = None
|
|
|
|
self.relaxation_time = None
|
|
|
|
self.miluphcuda_time = None
|
|
|
|
self.setup_time = None
|
2019-02-12 18:56:05 +01:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def from_dict(cls, data: dict):
|
|
|
|
sim = cls()
|
|
|
|
for key in data:
|
|
|
|
setattr(sim, key, data[key])
|
|
|
|
return sim
|
|
|
|
|
|
|
|
@property
|
|
|
|
def gamma(self) -> float:
|
|
|
|
return self.projectile_mass / self.target_mass
|
|
|
|
|
|
|
|
@property
|
|
|
|
def relative_projectile_mass(self) -> float:
|
|
|
|
return self.projectile_mass / self.total_mass
|
|
|
|
|
|
|
|
@property
|
|
|
|
def relative_target_mass(self) -> float:
|
|
|
|
return self.target_mass / self.total_mass
|
|
|
|
|
|
|
|
@property
|
|
|
|
def largest_aggregate_relative_mass(self) -> float:
|
|
|
|
"""
|
|
|
|
p['mS1_over_mt'] = p['mS1'] / p['mt']
|
|
|
|
"""
|
|
|
|
return self.largest_aggregate_mass / self.target_mass
|
|
|
|
|
2021-03-08 13:25:11 +01:00
|
|
|
@property
|
|
|
|
def largest_aggregate_mantle_fraction(self) -> float:
|
|
|
|
return 1 - self.largest_aggregate_core_fraction - self.largest_aggregate_water_fraction
|
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
@property
|
|
|
|
def second_largest_aggregate_relative_mass(self) -> float:
|
|
|
|
"""
|
|
|
|
p['mS2_over_mp'] = p['mS2'] / p['mp']
|
|
|
|
"""
|
|
|
|
return self.second_largest_aggregate_mass / self.projectile_mass
|
|
|
|
|
2019-08-21 12:54:27 +02:00
|
|
|
@property
|
2021-03-08 13:25:11 +01:00
|
|
|
def second_largest_aggregate_mantle_fraction(self) -> float:
|
|
|
|
return 1 - self.second_largest_aggregate_core_fraction - self.second_largest_aggregate_water_fraction
|
|
|
|
|
|
|
|
@property
|
|
|
|
def projectile_mantle_fraction(self):
|
|
|
|
return 1 - self.projectile_water_fraction - self.projectile_core_fraction
|
2019-08-21 12:54:27 +02:00
|
|
|
|
|
|
|
@property
|
2021-03-08 13:25:11 +01:00
|
|
|
def target_mantle_fraction(self):
|
|
|
|
return 1 - self.target_water_fraction - self.target_core_fraction
|
2019-08-21 12:54:27 +02:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
@property
|
|
|
|
def initial_water_mass(self) -> float:
|
|
|
|
return self.projectile_mass * self.projectile_water_fraction + self.target_mass * self.target_water_fraction
|
|
|
|
|
2019-08-21 12:54:27 +02:00
|
|
|
@property
|
2021-03-08 13:25:11 +01:00
|
|
|
def initial_core_mass(self) -> float:
|
|
|
|
return self.projectile_mass * self.projectile_core_fraction + self.target_mass * self.target_core_fraction
|
|
|
|
|
|
|
|
@property
|
|
|
|
def initial_mantle_mass(self) -> float:
|
|
|
|
return self.projectile_mass * self.projectile_mantle_fraction + self.target_mass * self.target_mantle_fraction
|
2019-08-21 12:54:27 +02:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
@property
|
|
|
|
def water_retention_both(self) -> float:
|
|
|
|
"""
|
|
|
|
p['wretentionB'] = (p['mS1'] * p['wmfS1'] + p['mS2'] * p['wmfS2']) / (p['mp'] * p['wp'] + p['mt'] * p['wt'])
|
|
|
|
"""
|
|
|
|
return (
|
|
|
|
self.largest_aggregate_mass * self.largest_aggregate_water_fraction
|
|
|
|
+ self.second_largest_aggregate_mass * self.second_largest_aggregate_water_fraction
|
|
|
|
) / self.initial_water_mass
|
|
|
|
|
2019-07-06 13:24:48 +02:00
|
|
|
@property
|
2021-03-08 13:25:11 +01:00
|
|
|
def core_retention_both(self) -> float:
|
|
|
|
return (
|
|
|
|
self.largest_aggregate_mass * self.largest_aggregate_core_fraction
|
|
|
|
+ self.second_largest_aggregate_mass * self.largest_aggregate_core_fraction
|
|
|
|
) / self.initial_core_mass
|
|
|
|
|
|
|
|
@property
|
|
|
|
def mantle_retention_both(self) -> float:
|
2019-08-21 12:54:27 +02:00
|
|
|
return (
|
2021-03-08 13:25:11 +01:00
|
|
|
self.largest_aggregate_mass * self.largest_aggregate_mantle_fraction
|
|
|
|
+ self.second_largest_aggregate_mass * self.largest_aggregate_mantle_fraction
|
|
|
|
) / self.initial_mantle_mass
|
2019-07-06 13:24:48 +02:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
@property
|
|
|
|
def water_retention_main(self) -> float:
|
|
|
|
"""
|
|
|
|
p['wretention1'] = p['mS1'] * p['wmfS1'] / (p['mp'] * p['wp'] + p['mt'] * p['wt'])
|
|
|
|
"""
|
|
|
|
return self.largest_aggregate_mass * self.largest_aggregate_water_fraction / self.initial_water_mass
|
|
|
|
|
2021-03-29 15:02:46 +02:00
|
|
|
@property
|
|
|
|
def output_mass_fraction(self) -> Optional[float]:
|
|
|
|
if not self.largest_aggregate_mass:
|
|
|
|
return 0 # FIXME
|
2021-10-12 15:45:43 +02:00
|
|
|
massive_size_relation=self.largest_aggregate_mass/self.target_mass
|
|
|
|
less_massive_size_relation=self.second_largest_aggregate_mass/self.projectile_mass
|
|
|
|
print("mr",massive_size_relation, less_massive_size_relation)
|
|
|
|
return less_massive_size_relation / massive_size_relation
|
2021-03-29 15:02:46 +02:00
|
|
|
|
2019-07-29 14:23:22 +02:00
|
|
|
@property
|
|
|
|
def original_simulation(self) -> bool:
|
|
|
|
return self.type == "original"
|
|
|
|
|
|
|
|
@property
|
|
|
|
def testcase(self) -> bool:
|
2021-03-08 13:25:11 +01:00
|
|
|
return self.type == "cloud" and 529 <= self.runid <= 631
|
2019-07-29 14:23:22 +02:00
|
|
|
|
2019-02-13 12:53:17 +01:00
|
|
|
@property
|
|
|
|
def simulation_key(self):
|
|
|
|
return "id{:04d}_v{:.1f}_a{:.0f}_m{:.0f}_g{:.1f}_wt{:.1f}_wp{:.1f}".format(
|
|
|
|
self.runid, self.vcode, self.alphacode, self.mcode, self.gammacode, self.wtcode, self.wpcode
|
|
|
|
)
|
2019-07-06 13:24:48 +02:00
|
|
|
|
2019-02-13 12:53:17 +01:00
|
|
|
def __repr__(self):
|
2021-10-12 15:45:43 +02:00
|
|
|
return f"<Simulation '{vars(self)}'>"
|
2019-02-13 12:53:17 +01:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
def load_params_from_dirname(self, dirname: str) -> None:
|
|
|
|
params = dirname.split("_")
|
|
|
|
self.runid = int(params[0][2:])
|
|
|
|
self.vcode = float(params[1][1:])
|
|
|
|
self.alphacode = float(params[2][1:])
|
|
|
|
self.mcode = float(params[3][1:])
|
|
|
|
self.gammacode = float(params[4][1:])
|
|
|
|
self.wtcode = float(params[5][2:])
|
|
|
|
self.wpcode = float(params[6][2:])
|
2019-02-13 12:53:17 +01:00
|
|
|
assert dirname == self.simulation_key
|
2019-02-12 18:56:05 +01:00
|
|
|
|
2019-07-06 13:24:48 +02:00
|
|
|
def load_params_from_json(self, paramfile: str) -> None:
|
|
|
|
with open(paramfile) as f:
|
|
|
|
data = json.load(f)
|
|
|
|
self.runid = int(data["run_id"])
|
|
|
|
self.vcode = data["v_code"]
|
|
|
|
self.alphacode = data["alpha_code"]
|
|
|
|
self.mcode = data["m_code"]
|
|
|
|
self.gammacode = data["gamma_code"]
|
|
|
|
self.wtcode = data["wt_code"]
|
|
|
|
self.wpcode = data["wp_code"]
|
|
|
|
|
2021-10-12 15:45:43 +02:00
|
|
|
def load_params_from_setup_txt(self, file: Path) -> None:
|
|
|
|
with file.open() as f:
|
|
|
|
data = yaml.safe_load(f)
|
|
|
|
# self.runid=data["ID"]
|
|
|
|
# self.vcode=data["vel_vesc_touching_ball"]
|
|
|
|
# self.alphacode=data["impact_angle_touching_ball"]
|
|
|
|
# self.mcode=data["M_tot"]
|
|
|
|
# self.gammacode=data["gamma"]
|
|
|
|
# TODO: maybe more needed?
|
|
|
|
|
|
|
|
def load_params_from_spheres_ini_log(self, filename: Path) -> None:
|
|
|
|
with filename.open() as f:
|
2019-02-12 18:56:05 +01:00
|
|
|
lines = [line.rstrip("\n") for line in f]
|
|
|
|
for i in range(len(lines)):
|
|
|
|
line = lines[i]
|
|
|
|
if "Geometry:" in line:
|
|
|
|
self.v = float(lines[i + 2].split(" = ")[-1])
|
2020-11-30 12:58:50 +01:00
|
|
|
print(lines[i + 3])
|
|
|
|
# self.alpha = float(lines[i + 3].split(" = ")[-1][:-1]) #for old format
|
|
|
|
self.alpha = float(lines[i + 3].split(" = ")[-1].split(" ")[0])
|
2019-02-12 18:56:05 +01:00
|
|
|
if "Masses:" in line:
|
|
|
|
self.total_mass = float(lines[i + 2].split()[3])
|
|
|
|
self.projectile_mass = float(lines[i + 4].split()[3])
|
|
|
|
self.target_mass = float(lines[i + 6].split()[3])
|
|
|
|
if "Mantle/shell mass fractions:" in line:
|
|
|
|
self.projectile_water_fraction = float(lines[i + 1].split()[7])
|
|
|
|
self.target_water_fraction = float(lines[i + 3].split()[7])
|
2020-11-30 12:58:50 +01:00
|
|
|
if "Particle numbers" in line:
|
2021-10-12 15:45:43 +02:00
|
|
|
self.desired_N = int(lines[i + 1].split()[4])
|
2020-11-30 12:58:50 +01:00
|
|
|
self.actual_N = int(lines[i + 1].split()[-1])
|
2019-02-12 18:56:05 +01:00
|
|
|
|
2021-10-12 15:45:43 +02:00
|
|
|
def load_params_from_aggregates_txt(self, filename: Path) -> None:
|
|
|
|
with filename.open() as f:
|
2019-02-12 18:56:05 +01:00
|
|
|
lines = [line.rstrip("\n") for line in f]
|
|
|
|
for i in range(len(lines)):
|
|
|
|
line = lines[i]
|
2020-11-30 12:58:50 +01:00
|
|
|
if "# largest aggregate" in line:
|
2021-10-12 15:45:43 +02:00
|
|
|
cols = lines[i + 2].split()
|
|
|
|
self.largest_aggregate_mass = float(cols[0])
|
|
|
|
self.largest_aggregate_core_fraction = float(cols[1])
|
|
|
|
self.largest_aggregate_water_fraction = 1 - float(cols[2]) - self.largest_aggregate_core_fraction
|
2020-11-30 12:58:50 +01:00
|
|
|
if "# 2nd-largest aggregate:" in line:
|
2021-10-12 15:45:43 +02:00
|
|
|
cols = lines[i + 2].split()
|
|
|
|
self.second_largest_aggregate_mass = float(cols[0])
|
|
|
|
self.second_largest_aggregate_core_fraction = float(cols[1])
|
|
|
|
self.second_largest_aggregate_water_fraction = 1 - float(
|
|
|
|
cols[2]) - self.second_largest_aggregate_core_fraction
|
2020-11-30 12:58:50 +01:00
|
|
|
if "# distance" in line: # TODO: not sure if correct anymore
|
2019-02-12 18:56:05 +01:00
|
|
|
self.distance = float(lines[i + 1].split()[0])
|
|
|
|
self.rel_velocity = float(lines[i + 1].split()[1])
|
|
|
|
self.rel_velocity_per_esc_velocity = float(lines[i + 1].split()[2])
|
|
|
|
|
2020-11-30 12:58:50 +01:00
|
|
|
def load_params_from_pythontiming_json(self, filename: str) -> None:
|
|
|
|
with open(filename) as f:
|
|
|
|
data = json.load(f)
|
2021-03-08 13:25:11 +01:00
|
|
|
self.miluphcuda_time = data["miluphcuda"]
|
|
|
|
self.relaxation_time = data["relaxation"]
|
|
|
|
self.setup_time = data["setup"]
|
2020-11-30 12:58:50 +01:00
|
|
|
|
2019-02-12 18:56:05 +01:00
|
|
|
def assert_all_loaded(self) -> None:
|
|
|
|
for key, value in self.__dict__.items():
|
2020-11-30 12:58:50 +01:00
|
|
|
print(key, value)
|
2019-02-12 18:56:05 +01:00
|
|
|
assert value is not None
|