-
Notifications
You must be signed in to change notification settings - Fork 0
/
simulate_orbits.py
108 lines (91 loc) · 4.23 KB
/
simulate_orbits.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import warnings
from pathlib import Path
from typing import Any, Dict, Union
import click
import yaml
from norbit import Animator, Orbiter, Plotter
warnings.filterwarnings("ignore")
def load_config(config_path: Union[str, Path]) -> Dict[str, Any]:
"""Load a YAML config file as a `dict`.
Args:
config_path (Union[str, Path]): Path to the YAML config file.
Returns:
Dict[str, Any]: `dict` containing simulation settings.
"""
with open(config_path, "r") as infile:
return yaml.safe_load(infile)
class Simulator:
def __init__(self, config: Dict[str, Any], orbital_system: Orbiter) -> None:
"""Instantiate a `Simulator` to run an N-body numerical simulation.
Args:
config (Dict[str, Any]): Simulation settings for the orbital system.
orbital_system (Orbiter): A newly instantiated, unsolved orbital system, or
a solved orbital system, loaded from a PKL file. Note that the config
specifies whether the orbital system is loaded or not during `Orbiter`
instantiation.
"""
self.config = config
self.orbital_system = orbital_system
def simulate(self) -> None:
"""Run the orbital N-body simulation according to the provided config."""
if self.config["run_simulation"]["enabled"]:
self.orbital_system.get_orbits()
self.orbital_system.get_potential_qtys()
self.orbital_system.get_kinetic_qtys()
if self.config["run_simulation"]["save_data"]:
self.orbital_system.save()
def create_visuals(self):
"""Create visuals for a solved orbital system based on the provided config."""
self.plotter = Plotter(self.orbital_system)
self.animator = Animator(self.orbital_system)
all = self.config["plots"]["all"]
if all or self.config["plots"]["orbits"]["3d"]:
self.plotter.plot_3d_orbits()
self.animator.animate_3d_orbits()
if all or self.config["plots"]["orbits"]["x"]:
self.plotter.plot_3d_orbits_viewed_from_pos_axis("x")
if all or self.config["plots"]["orbits"]["y"]:
self.plotter.plot_3d_orbits_viewed_from_pos_axis("y")
if all or self.config["plots"]["orbits"]["z"]:
self.plotter.plot_3d_orbits_viewed_from_pos_axis("z")
if all or self.config["plots"]["e_sys"]:
self.plotter.plot_e_sys_vs_t()
if all or self.config["plots"]["ke_tot"]:
self.plotter.plot_ke_tot_vs_t()
if all or self.config["plots"]["pe_tot"]:
self.plotter.plot_pe_tot_vs_t()
if all or self.config["plots"]["phase_space"]["p"]["x"]:
self.plotter.plot_phase_space("p", "x")
if all or self.config["plots"]["phase_space"]["p"]["y"]:
self.plotter.plot_phase_space("p", "y")
if all or self.config["plots"]["phase_space"]["p"]["z"]:
self.plotter.plot_phase_space("p", "z")
if all or self.config["plots"]["phase_space"]["pe"]["x"]:
self.plotter.plot_phase_space("pe", "x")
if all or self.config["plots"]["phase_space"]["pe"]["y"]:
self.plotter.plot_phase_space("pe", "y")
if all or self.config["plots"]["phase_space"]["pe"]["z"]:
self.plotter.plot_phase_space("pe", "z")
if all or self.config["plots"]["phase_space"]["ke"]["x"]:
self.plotter.plot_phase_space("ke", "x")
if all or self.config["plots"]["phase_space"]["ke"]["y"]:
self.plotter.plot_phase_space("ke", "y")
if all or self.config["plots"]["phase_space"]["ke"]["z"]:
self.plotter.plot_phase_space("ke", "z")
@click.command()
@click.argument(
"config_path", default="configs/config.yaml", type=click.Path(exists=True)
)
def main(config_path: str) -> None:
"""Run an orbital simulation specified by an associated YAML config file.
Args:
config_path (str): Path to the YAML config containing simulation settings.
"""
config = load_config(config_path)
print(f"{config["ic"]}, {config["N"]} bodies")
orbital_system = Orbiter(config)
simulator = Simulator(config, orbital_system)
simulator.simulate()
simulator.create_visuals()
if __name__ == "__main__":
main()