it WORKS!
This commit is contained in:
parent
cf81cd17e6
commit
5e3d043af4
@ -1,7 +1,8 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from ..units import Position, Velocity, Mass, Acceleration
|
from ..units import *
|
||||||
|
from .calc import format_sig_figs
|
||||||
|
|
||||||
class Body:
|
class Body:
|
||||||
"""
|
"""
|
||||||
@ -25,10 +26,32 @@ class Body:
|
|||||||
return cls(tup[0], tup[1], tup[2])
|
return cls(tup[0], tup[1], tup[2])
|
||||||
|
|
||||||
def step(self, step_size: float):
|
def step(self, step_size: float):
|
||||||
self.X = step_size*self.V
|
self.X += step_size*self.V
|
||||||
self.V = step_size*self.A
|
self.V += step_size*self.A
|
||||||
|
self.A = HighPrecisionVector([0,0,0])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(f"{self.name}: X = {self.X}, V = {self.V}")
|
pos = 'm '.join([format_sig_figs(real_pos(x), 3) for x in self.X])
|
||||||
|
vel = 'm/s '.join([format_sig_figs(real_vel(v), 3) for v in self.V])
|
||||||
|
return str(f"{self.name}: X = {pos}, V = {vel}")
|
||||||
|
|
||||||
|
def E(self):
|
||||||
|
return self.ke() + self.pe()
|
||||||
|
|
||||||
|
def pe(self):
|
||||||
|
return -self.m/self.dist_from_o()
|
||||||
|
|
||||||
|
def dist_from_o(self):
|
||||||
|
return sum([x**2 for x in self.X]).sqrt()
|
||||||
|
|
||||||
|
|
||||||
|
def ke(self):
|
||||||
|
return Decimal(0.5)*self.m*(self._speed()**2)
|
||||||
|
|
||||||
|
def _speed(self):
|
||||||
|
return sum([v**2 for v in self.V]).sqrt()
|
||||||
|
|
||||||
|
def speed(self):
|
||||||
|
return str(f"{format_sig_figs(real_vel(self._speed),5)}")
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
import sys
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from time import time
|
||||||
|
|
||||||
from ..units import HighPrecisionMatrix
|
from ..units import HighPrecisionMatrix
|
||||||
|
|
||||||
@ -13,3 +15,63 @@ def calculate_distances(positions):
|
|||||||
dists[i][j] = Decimal(d)
|
dists[i][j] = Decimal(d)
|
||||||
dists[j][i] = Decimal(d)
|
dists[j][i] = Decimal(d)
|
||||||
return dists
|
return dists
|
||||||
|
|
||||||
|
def print_progress_bar(iteration, total, start_time, length=50):
|
||||||
|
"""Prints a progress bar to the console."""
|
||||||
|
percent = (iteration / total) * 100
|
||||||
|
filled_length = int(length * iteration // total)
|
||||||
|
bar = '#' * filled_length + '-' * (length - filled_length)
|
||||||
|
sys.stdout.write(f'\r[{bar}] {percent:.2f}% {int(iteration/(time()-start_time))} steps/s')
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def format_sig_figs(value, sig_figs):
|
||||||
|
"""Format a number to a specified number of significant figures for printing."""
|
||||||
|
if value == 0:
|
||||||
|
return "0"
|
||||||
|
return f"{value:.{sig_figs-1}e}"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def plot_points_terminal(vectors, stdscr, scale=500000, grid_width=30, grid_height=30):
|
||||||
|
"""Plots multiple points in the terminal, scaled and centered at (0,0)."""
|
||||||
|
stdscr.clear()
|
||||||
|
|
||||||
|
if not vectors:
|
||||||
|
stdscr.addstr(0, 0, "No vectors provided.")
|
||||||
|
stdscr.refresh()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Apply scaling
|
||||||
|
scaled_vectors = {(round(vec[0] / scale), round(vec[1] / scale)) for vec in vectors}
|
||||||
|
|
||||||
|
# Find min and max coordinates
|
||||||
|
min_x = min(vec[0] for vec in scaled_vectors)
|
||||||
|
max_x = max(vec[0] for vec in scaled_vectors)
|
||||||
|
min_y = min(vec[1] for vec in scaled_vectors)
|
||||||
|
max_y = max(vec[1] for vec in scaled_vectors)
|
||||||
|
|
||||||
|
# Center offsets to keep (0,0) in middle
|
||||||
|
center_x = (grid_width // 2) - min_x
|
||||||
|
center_y = (grid_height // 2) - min_y
|
||||||
|
|
||||||
|
# Adjust coordinates for plotting
|
||||||
|
adjusted_vectors = {(vec[0] + center_x, vec[1] + center_y) for vec in scaled_vectors}
|
||||||
|
|
||||||
|
# Ensure grid boundaries
|
||||||
|
max_terminal_y, max_terminal_x = stdscr.getmaxyx()
|
||||||
|
max_x = min(grid_width, max_terminal_x - 5)
|
||||||
|
max_y = min(grid_height, max_terminal_y - 5)
|
||||||
|
|
||||||
|
# Draw grid with points
|
||||||
|
for i in range(grid_height, -1, -1):
|
||||||
|
row = f"{i - center_y:2} | "
|
||||||
|
for j in range(grid_width + 1):
|
||||||
|
row += "● " if (j, i) in adjusted_vectors else ". "
|
||||||
|
stdscr.addstr(max_y - i, 0, row[:max_terminal_x - 1]) # Ensure no overflow
|
||||||
|
|
||||||
|
# Print X-axis labels
|
||||||
|
x_labels = " " + " ".join(f"{j - center_x:2}" for j in range(max_x + 1))
|
||||||
|
stdscr.addstr(max_y + 1, 0, x_labels[:max_terminal_x - 1]) # Avoid out-of-bounds error
|
||||||
|
|
||||||
|
stdscr.refresh()
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from decimal import InvalidOperation, DivisionByZero
|
from decimal import InvalidOperation, DivisionByZero
|
||||||
|
from time import time
|
||||||
|
|
||||||
from .body import Body
|
from .body import Body
|
||||||
from .calc import calculate_distances
|
from .calc import *
|
||||||
from ..units import HighPrecisionVector
|
from ..units import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -106,13 +107,31 @@ class Simulator:
|
|||||||
steps=stepsz_n_np)
|
steps=stepsz_n_np)
|
||||||
|
|
||||||
def run(self, steps):
|
def run(self, steps):
|
||||||
|
time_start = time()
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
plt.ion()
|
||||||
|
fig, ax = plt.subplots()
|
||||||
|
x_data, y_data =[],[]
|
||||||
|
line, = ax.plot(x_data, y_data, 'bo-')
|
||||||
|
ax.set_xlim(-8e6,8e6)
|
||||||
|
ax.set_ylim(-8e6,8e6)
|
||||||
for i in range(steps):
|
for i in range(steps):
|
||||||
#print(f"On the {i}th step - vel {self.bodies[1].V}")
|
|
||||||
self.calculate_forces()
|
self.calculate_forces()
|
||||||
self.move_bodies()
|
self.move_bodies()
|
||||||
self.current_step += 1
|
self.current_step += 1
|
||||||
if (self.current_step % self.steps_per_save == 0):
|
if (self.current_step % self.steps_per_save == 0):
|
||||||
self._checkpoint()
|
for b in self.bodies:
|
||||||
|
x_data.append(int(real_pos(b.X[0])))
|
||||||
|
y_data.append(int(real_pos(b.X[1])))
|
||||||
|
line.set_xdata(x_data)
|
||||||
|
line.set_ydata(y_data)
|
||||||
|
plt.draw()
|
||||||
|
plt.pause(0.2)
|
||||||
|
x_data, y_data =[],[]
|
||||||
|
|
||||||
|
|
||||||
|
#print_progress_bar(i, steps, time_start)
|
||||||
|
#self._checkpoint()
|
||||||
|
|
||||||
def calculate_forces(self):
|
def calculate_forces(self):
|
||||||
positions = [
|
positions = [
|
||||||
@ -120,21 +139,14 @@ class Simulator:
|
|||||||
]
|
]
|
||||||
dists = calculate_distances(positions)
|
dists = calculate_distances(positions)
|
||||||
for i in range(len(self.bodies)):
|
for i in range(len(self.bodies)):
|
||||||
print(str(self.bodies[i]))
|
for j in range(i, len(self.bodies)):
|
||||||
force_sum = HighPrecisionVector([0.0, 0.0, 0.0])
|
|
||||||
for j in range(len(self.bodies)):
|
|
||||||
if i == j:
|
if i == j:
|
||||||
continue
|
continue
|
||||||
vec = self.bodies[i].X - self.bodies[j].X
|
vec = self.bodies[i].X - self.bodies[j].X
|
||||||
norm = np.linalg.norm(vec)
|
f = vec/(dists[i][j]**3)
|
||||||
try:
|
self.bodies[i].A += f*self.bodies[j].m
|
||||||
vec_norm = vec/norm
|
self.bodies[j].A += f*self.bodies[i].m
|
||||||
f = self.bodies[i].m*self.bodies[j].m/(dists[i][j]**2)
|
|
||||||
except (InvalidOperation, DivisionByZero):
|
|
||||||
vec_norm = HighPrecisionVector([0,0,0])
|
|
||||||
f = 0
|
|
||||||
force_sum += vec_norm*f
|
|
||||||
self.bodies[i].A = force_sum/self.bodies[i].m
|
|
||||||
|
|
||||||
def move_bodies(self):
|
def move_bodies(self):
|
||||||
for body in self.bodies:
|
for body in self.bodies:
|
||||||
|
@ -10,7 +10,6 @@ class HighPrecisionVector(np.ndarray):
|
|||||||
|
|
||||||
class HighPrecisionMatrix(np.ndarray):
|
class HighPrecisionMatrix(np.ndarray):
|
||||||
def __new__(cls, dim1, dim2, *args, **kwargs):
|
def __new__(cls, dim1, dim2, *args, **kwargs):
|
||||||
print(f"dim1{dim1}, dim2{dim2}")
|
|
||||||
decimal_array = [Decimal(0) for _ in range(dim1)]
|
decimal_array = [Decimal(0) for _ in range(dim1)]
|
||||||
decimal_matrix = [decimal_array for _ in range(dim2)]
|
decimal_matrix = [decimal_array for _ in range(dim2)]
|
||||||
obj = np.asarray(decimal_matrix).view(cls)
|
obj = np.asarray(decimal_matrix).view(cls)
|
||||||
@ -39,6 +38,9 @@ MOON_ORBITAL_VELOCITY = Decimal(1022) #m/s relative to earth
|
|||||||
SUN_MASS = Decimal(1989 * 10**27) #kg
|
SUN_MASS = Decimal(1989 * 10**27) #kg
|
||||||
SUN_RADIUS = Decimal(6957 * 10**5) #meters
|
SUN_RADIUS = Decimal(6957 * 10**5) #meters
|
||||||
|
|
||||||
|
pi_approx = Decimal("3.14159265358979323846264338327950288419716939937510")
|
||||||
|
|
||||||
|
|
||||||
#NORMALIZING CONSTANTS
|
#NORMALIZING CONSTANTS
|
||||||
G = Decimal(6.67430e-11)
|
G = Decimal(6.67430e-11)
|
||||||
r_0 = Decimal(EARTH_RADIUS) #1.496e11
|
r_0 = Decimal(EARTH_RADIUS) #1.496e11
|
||||||
@ -49,7 +51,7 @@ def norm_pos(pos):
|
|||||||
return Decimal(pos) / Decimal(r_0)
|
return Decimal(pos) / Decimal(r_0)
|
||||||
|
|
||||||
def real_pos(pos):
|
def real_pos(pos):
|
||||||
return Decimal(pos) * Decimal(r_0)
|
return pos * Decimal(r_0)
|
||||||
|
|
||||||
def norm_mass(mass):
|
def norm_mass(mass):
|
||||||
return Decimal(mass) / Decimal(m_0)
|
return Decimal(mass) / Decimal(m_0)
|
||||||
@ -64,9 +66,9 @@ def real_time(time):
|
|||||||
return Decimal(time) * Decimal(t_0)
|
return Decimal(time) * Decimal(t_0)
|
||||||
|
|
||||||
def norm_vel(vel):
|
def norm_vel(vel):
|
||||||
return Decimal(vel) / Decimal(r_0/t_0)
|
return vel / Decimal(r_0/t_0)
|
||||||
|
|
||||||
def real_vel(vel):
|
def real_vel(vel):
|
||||||
return Decimal(vel) * Decimal(r_0/t_0)
|
return vel * Decimal(r_0/t_0)
|
||||||
|
|
||||||
|
|
||||||
|
28
test.py
28
test.py
@ -5,7 +5,7 @@ from orbiter.units import *
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decimal import Decimal, getcontext
|
from decimal import Decimal, getcontext
|
||||||
|
|
||||||
getcontext().prec = 100
|
getcontext().prec = 50
|
||||||
|
|
||||||
#set up the earth
|
#set up the earth
|
||||||
earth = Body(
|
earth = Body(
|
||||||
@ -15,19 +15,29 @@ earth = Body(
|
|||||||
"Earth"
|
"Earth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
r = EARTH_RADIUS+100_000
|
||||||
#Lets try a body just outside earth accelerating in. Should be 9.8m/s2
|
#Lets try a body just outside earth accelerating in. Should be 9.8m/s2
|
||||||
person = Body(
|
person = Body(
|
||||||
Position([norm_pos(EARTH_RADIUS+100_000),0,0]), #10_000m in the sky, airliner height!
|
Position([norm_pos(r),0,0]), #10_000m in the sky, airliner height!
|
||||||
Velocity([0,0,0]), #start from standstill
|
Velocity([0,(Decimal(0.5)/norm_pos(r)).sqrt(),0]), #orbital velocity
|
||||||
Mass(norm_mass(80)), #avg person
|
Mass(norm_mass(80)), #avg person
|
||||||
"Person"
|
"Person"
|
||||||
)
|
)
|
||||||
|
|
||||||
time_to_run = norm_time(5)
|
T = 2*pi_approx*norm_pos(r)/person.V[1]
|
||||||
STEP_SIZE = Decimal(1e-10)
|
|
||||||
n_steps = time_to_run/STEP_SIZE
|
|
||||||
|
|
||||||
s = Simulator([earth,person], STEP_SIZE, 1, Path("hello_world"))
|
time_to_run = 15 #norm_time(2000)
|
||||||
s.run(10)
|
STEP_SIZE = Decimal(6e-4)
|
||||||
|
n_steps = int(time_to_run/STEP_SIZE)
|
||||||
|
|
||||||
print(real_vel(person.V))
|
def main():
|
||||||
|
print("Before: ")
|
||||||
|
print(str(person))
|
||||||
|
print(str(earth))
|
||||||
|
s = Simulator([earth,person], STEP_SIZE, 100, Path("hello_world"))
|
||||||
|
s.run(n_steps)
|
||||||
|
print("\nAfter:")
|
||||||
|
print(str(person))
|
||||||
|
print(str(earth))
|
||||||
|
|
||||||
|
main()
|
Loading…
x
Reference in New Issue
Block a user