From ddd59471236496dbcf95c625d99aca16fcc189e1 Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:26:02 -0400 Subject: [PATCH 1/9] Delete orbiter/orbits/__init__.py --- orbiter/orbits/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 orbiter/orbits/__init__.py diff --git a/orbiter/orbits/__init__.py b/orbiter/orbits/__init__.py deleted file mode 100644 index e69de29..0000000 From abf652adab2a0c6a406abd29a7467c5dee55b074 Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:26:11 -0400 Subject: [PATCH 2/9] Delete orbiter/orbits/body.py --- orbiter/orbits/body.py | 57 ------------------------------------------ 1 file changed, 57 deletions(-) delete mode 100644 orbiter/orbits/body.py diff --git a/orbiter/orbits/body.py b/orbiter/orbits/body.py deleted file mode 100644 index 676245f..0000000 --- a/orbiter/orbits/body.py +++ /dev/null @@ -1,57 +0,0 @@ -from enum import Enum -import numpy as np - -from ..units import * -from .calc import format_sig_figs - -class Body: - """ - Base class for any orbital body - """ - def __init__(self, X: Position, V: Velocity, m: Mass, name: str = ""): - """ - x (position) and v (velocity) - """ - self.X = X - self.V = V - self.A = Acceleration([0,0,0]) - self.m = m - self.name = name - - def save(self): - return (self.X, self.V, self.m) - - @classmethod - def load(cls, tup): - return cls(tup[0], tup[1], tup[2]) - - def step(self, step_size: float): - self.X += step_size*self.V - self.V += step_size*self.A - self.A = HighPrecisionVector([0,0,0]) - - def __str__(self): - 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)}") - - From 9ba4da4db37c94cfc9791bf3c6d182e663558004 Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:26:14 -0400 Subject: [PATCH 3/9] Delete orbiter/orbits/calc.py --- orbiter/orbits/calc.py | 84 ------------------------------------------ 1 file changed, 84 deletions(-) delete mode 100644 orbiter/orbits/calc.py diff --git a/orbiter/orbits/calc.py b/orbiter/orbits/calc.py deleted file mode 100644 index 6bc0afa..0000000 --- a/orbiter/orbits/calc.py +++ /dev/null @@ -1,84 +0,0 @@ -import numpy as np -import sys -from decimal import Decimal -from time import time - -from ..units import HighPrecisionMatrix - -def calculate_distances(positions): - N = len(positions) - dists = HighPrecisionMatrix(N,N) - for i in range(N): - dists[i][i] = Decimal(0) - for j in range(i+1, N): - d = sum([x**2 for x in (positions[i]-positions[j])]).sqrt() - dists[i][j] = Decimal(d) - dists[j][i] = Decimal(d) - return dists - -def calculate_distances_np(positions): - positions = np.array(positions) - diffs = positions[:, np.newaxis] - positions[np.newaxis, :] - dists = np.linalg.norm(diffs, axis=-1) - np.fill_diagonal(dists, 0) - 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() From 1c9fb9b6931ed749a7dfaf9bce1bc05e19551d12 Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:28:29 -0400 Subject: [PATCH 4/9] Delete orbiter/orbits/simulator.py --- orbiter/orbits/simulator.py | 136 ------------------------------------ 1 file changed, 136 deletions(-) delete mode 100644 orbiter/orbits/simulator.py diff --git a/orbiter/orbits/simulator.py b/orbiter/orbits/simulator.py deleted file mode 100644 index 655f973..0000000 --- a/orbiter/orbits/simulator.py +++ /dev/null @@ -1,136 +0,0 @@ -from pathlib import Path -import numpy as np -from decimal import InvalidOperation, DivisionByZero -from time import time - -from .body import Body -from .calc import * -from ..units import * - - - -class Simulator: - """ - Everything a simulator needs to run: - - a step size - - bodies with initial positions and momenta - - number of steps to take - - a reset mechanism - - a checkpoint mechanism - - how often to save? - - overwrite output file if exists? default false - if output file is a saved checkpoint file, then use the - from_checkpoint class method to create the class. - - otherwise if the output file exists, class will not start. - - output is as text: - first line of file is list of masses of bodies - each subsequent line is list of positions and velocities of each bodies: - body1x, body1y, body1vx, body1vy, body2x, body2y, body2vx etc - - For some of these, it should come with sensible defaults with - the ability to change - """ - def __init__( - self, - bodies: list[Body], - step_size: float, - steps_per_save: int, - output_file: str, - current_step: int = 0, - overwrite_output: bool = False - ): - self.output_file = Path(output_file) - if output_file.exists() and not overwrite_output: - raise FileExistsError(f"File {output_file} exists and overwrite flag not given.") - - self.bodies = bodies - self.step_size = step_size - self.steps_per_save = steps_per_save - self.current_step = current_step - - if output_file.exists() and overwrite_output: - print(f"Warning! Overwriting file: {output_file}") - - self._checkpoint() - - - @classmethod - def from_checkpoint(cls, output_file: Path): - data = np.load("last_checkpoint.npz") - positions = data["positions"] - velocities = data["velocities"] - masses = data["masses"] - step_size = data["steps"][0] - current_step = data["steps"][1] - steps_per_save = data["steps"][2] - - bodies = [ - Body(val[0], val[1], val[2]) for val in zip( - positions, velocities, masses - ) - ] - return cls( - bodies, - step_size, - steps_per_save, - output_file, - current_step, - ) - - - def _checkpoint(self): - """ - Two things - save high precision last checkpoint for resuming - then save lower precision text for trajectories - """ - body_X_np = np.array([ - body.X for body in self.bodies - ]) - body_V_np = np.array([ - body.V for body in self.bodies - ]) - body_m_np = np.array([ - body.m for body in self.bodies - ]) - stepsz_n_np = np.array([ - self.step_size, - self.current_step, - self.steps_per_save - ]) - - np.savez("last_checkpoint.npz", - positions=body_X_np, - velocities=body_V_np, - masses=body_m_np, - steps=stepsz_n_np) - - def run(self, steps): - time_start = time() - for i in range(steps): - self.calculate_forces() - self.move_bodies() - self.current_step += 1 - if (self.current_step % self.steps_per_save == 0): - print_progress_bar(i, steps, time_start) - #self._checkpoint() - - def calculate_forces(self): - positions = [ - body.X for body in self.bodies - ] - dists = calculate_distances_np(positions) - for i in range(len(self.bodies)): - for j in range(i, len(self.bodies)): - if i == j: - continue - vec = self.bodies[i].X - self.bodies[j].X - f = vec/(dists[i][j]**3) - self.bodies[i].A += f*self.bodies[j].m - self.bodies[j].A += f*self.bodies[i].m - - - def move_bodies(self): - for body in self.bodies: - body.step(self.step_size) \ No newline at end of file From 7fb44153712c7c40bb53c61d55def609d19769ac Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:28:35 -0400 Subject: [PATCH 5/9] Delete orbiter/__init__.py --- orbiter/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 orbiter/__init__.py diff --git a/orbiter/__init__.py b/orbiter/__init__.py deleted file mode 100644 index e69de29..0000000 From 11a6549896d977a2af06fe763d75042a865c1ba8 Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:28:39 -0400 Subject: [PATCH 6/9] Delete orbiter/units.py --- orbiter/units.py | 74 ------------------------------------------------ 1 file changed, 74 deletions(-) delete mode 100644 orbiter/units.py diff --git a/orbiter/units.py b/orbiter/units.py deleted file mode 100644 index be121ae..0000000 --- a/orbiter/units.py +++ /dev/null @@ -1,74 +0,0 @@ -import numpy as np -from decimal import Decimal - -#Declare these as units to make code clearer -class HighPrecisionVector(np.ndarray): - def __new__(cls, input_array, *args, **kwargs): - decimal_array = [Decimal(i) for i in input_array] - obj = np.asarray(decimal_array).view(cls) - return obj - -class HighPrecisionMatrix(np.ndarray): - def __new__(cls, dim1, dim2, *args, **kwargs): - decimal_array = [Decimal(0) for _ in range(dim1)] - decimal_matrix = [decimal_array for _ in range(dim2)] - obj = np.asarray(decimal_matrix).view(cls) - return obj - -class Position(HighPrecisionVector): - pass -class Velocity(HighPrecisionVector): - pass -class Acceleration(HighPrecisionVector): - pass - -Mass = Decimal - -#################### -# USEFUL CONSTANTS -#################### -EARTH_MASS = Decimal(5972 * 10**21) #kg -EARTH_RADIUS = Decimal(6378 * 10**3) #meters -EARTH_ORBITAL_VELOCITY = Decimal(29780) # m/s -AU = Decimal(149_597_870_700) #meters - -MOON_MASS = Decimal(734767309 * 10**14) -MOON_ORBITAL_VELOCITY = Decimal(1022) #m/s relative to earth - -SUN_MASS = Decimal(1989 * 10**27) #kg -SUN_RADIUS = Decimal(6957 * 10**5) #meters - -pi_approx = Decimal("3.14159265358979323846264338327950288419716939937510") - - -#NORMALIZING CONSTANTS -G = Decimal(6.67430e-11) -r_0 = Decimal(EARTH_RADIUS) #1.496e11 -m_0 = Decimal(5.972e24) -t_0 = np.sqrt((r_0**3) / (G*m_0)) - -def norm_pos(pos): - return Decimal(pos) / Decimal(r_0) - -def real_pos(pos): - return pos * Decimal(r_0) - -def norm_mass(mass): - return Decimal(mass) / Decimal(m_0) - -def real_mass(mass): - return Decimal(mass) * Decimal(m_0) - -def norm_time(time): - return Decimal(time) / Decimal(t_0) - -def real_time(time): - return Decimal(time) * Decimal(t_0) - -def norm_vel(vel): - return vel / Decimal(r_0/t_0) - -def real_vel(vel): - return vel * Decimal(r_0/t_0) - - From b52c5d0801de81c435632f041ef40cc55d404b2c Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:28:43 -0400 Subject: [PATCH 7/9] Delete orbiter/orbits/__pycache__/__init__.cpython-312.pyc --- .../orbits/__pycache__/__init__.cpython-312.pyc | Bin 163 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 orbiter/orbits/__pycache__/__init__.cpython-312.pyc diff --git a/orbiter/orbits/__pycache__/__init__.cpython-312.pyc b/orbiter/orbits/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 7c8f0c8200fcedc2e9056ae8f36b042b6bc977c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmX@j%ge<81d5W@86f&Gh(HIQS%4zb87dhx8U0o=6fpsLpFwJVIq7HQ=cekHq$TE; z7U>rh Date: Mon, 2 Jun 2025 12:28:47 -0400 Subject: [PATCH 8/9] Delete orbiter/orbits/__pycache__/body.cpython-312.pyc --- orbiter/orbits/__pycache__/body.cpython-312.pyc | Bin 3915 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 orbiter/orbits/__pycache__/body.cpython-312.pyc diff --git a/orbiter/orbits/__pycache__/body.cpython-312.pyc b/orbiter/orbits/__pycache__/body.cpython-312.pyc deleted file mode 100644 index 9991296f41bc9a4de3b319d5c022906addf00a77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3915 zcmd59T}&Lud1n7ue$O0WgY7hHhXCs&#;#+G6W0z1yGdw}BUf&8RkgX?EO7Xah1~_r z`H=j;18x$5)kxqtm2n!$L8K~=ezc$R(3iufIM&vYQnfFWd&_}w^V*U2 zn{Vd(X6BpkclPhq)fEKVj~|{Iydo3wFB}w`6d;9eK;{V}jHXDM#wbNxNC`2KiA+jK ze-&UxW=cvHozNWW#L zMF2+GE`W8c7GV8kRIm4> zZi`K3^a>4Hcib_xL@Mq$8VIh%hbJ}5{wV3jQ`$$s#d$pXfk!WTH0?>l@wAx$9fu9| zE5cX!5Wqai(kw9m^IKMc5$c6EH(WOWR``-G2NdAJ9eB%%Fe=)NWF;7dt3dl=<_MPv zCBLk-jaW|7O;)S&5`OscRwIl4zriHbI}R*yt~IB>=CgE0Hi$rX9z9 zJlbVfA*mXGE_;$=rusLTH)#$Eg+gdQoo*kr(q_BcAGgNr_7U3}G83-T9w-sqAU&3f zyO!l z7k9k?@>70?i6SOW5MAlZ2x)B%6`GOK?T(gF-q1eKeg*xj+C}Jf)su#-Wa&V19k(zX2NUHaX=Hy-Tm&DZ>9Mtlsx&E}KWlXJgcR2H2@^Xrb4 zmsT2bbtm$X&Yar$bVDXh@6xB<-d+do^7;Pm-Rk|_`@8q4JLlLQVB$G;2M=5Z8aD96 zAWQjU9~P+@7+xSYcq67O;gabIBc{z067Cr!EP6Jha1EVpfk_8bALu4hH#>1{;^WDM z*KeJ;apLC5)kt$rZGJXj@OU0DrvZ6hNvQleK|vv*pu8}8l`QGFM!#*P4Qso|_7ONM zQ^tiJF?AR?m=3~1Ff%dde!r)6bx&)4kG>kwbE^KV;OJ~za2Jqy;)YuO+31FqQxvO4 z2BHz7w|r~#4ux+F*f?lKijsz*vEi9vy0!m zL_Jv73x072CtPg4({j7zVV%D4{#@7G=%0EX)ag)TzK^u8M%wd{qdE2HQ}* zgYfY9>41)>JNpDq1U2v#z)NeOjpZ&=>1Q*p9`pyh6TwLUThd7A-oFJ(sU_VoVQdx( zupB;ZwzXn%2iphr{3a>RfenSeH8eNWb$mi0L9#HI8WvRXDYb#9LGyL8UVCj z^fT+L!LQxFU0J%4Z+Y`>SAO^DT*H}sq${U(al`e&e-Y6e@P&)N4Tj-W7)IJ+V=2U| z3}bXGo(d?C`I(h~Y4v>YruWo~!DHT&-h5+e28*6dF`?B*Ng+yiZcpenmiE%S$(3Ya??WFI)QHS zGVfM;cy~`M;N(UR^({z0PuCJjH31OJhZ&~Cax5c0$S3$RG$h5!Hn From d82fb8b6282d345e30a9834347335c9c405be07a Mon Sep 17 00:00:00 2001 From: tfaour Date: Mon, 2 Jun 2025 12:28:50 -0400 Subject: [PATCH 9/9] Delete orbiter/orbits/__pycache__/simulator.cpython-312.pyc --- .../orbits/__pycache__/simulator.cpython-312.pyc | Bin 6147 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 orbiter/orbits/__pycache__/simulator.cpython-312.pyc diff --git a/orbiter/orbits/__pycache__/simulator.cpython-312.pyc b/orbiter/orbits/__pycache__/simulator.cpython-312.pyc deleted file mode 100644 index 1fcb39f28b36c344159a36273e1f643e38d08828..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6147 zcmcIoU2Gf25#BrA@%JQAKh*!v$(Ciawxu|5EZcDtIF_9RL6sU#lR%9@oOmbked)G%CPWQ$P~hH1ty(xJC1r*R+p)F(bPot_o_P4GO=}QsCBkC_1ypBPl^i zT%cW$yR(0@v%53j%-)~s>VgE)1^HCs*)So0!-|`@GO?8aVwuQ9W;Bvy#u)}_R%6FK zP>?>t1#ab)PGx-zjf4a720$T%aDaaLx=JpmFRa)Zn&oWgfNuk2C0GN<@t zUh&IbD1Ay`Qjq=E`0=0;f>vRYg$;0b$}Gq04wzmAtWe5IyYU>$bbIGe7T%;8)nNb&z2jWb?dWNM8%3b zCv#3WL=!X$#e{<~;m}psdqPiZa39z~Rnb&ZraA#PTfR<5L+Ot2IHd_yQ>}S=1E642 z&SlwNM_4<6njS+DDEp8Cl);X z!Scw~zad*D7QzKhS?*4m&XQP7>om^Tkz8vx8na%r!K(0=nJo7!fW`McF0Y?3SqAvI zFiNs4)G8da9;kU;=2;$U6<%5H8&?izy+*y&=+2crxbpj~yDmerWV+eyt(LCj44EfU zZY;x}L%YlDE887Kipu$klbSR|m3m5@RZ>HluD2v31whp=zFxLpL@m67lVUVz;JF&$ zL5S^jjKgj~_GhU{pEV5KFc5l;ddwOyL-}of#sCblLp25(_1T=MXp=j~BXc^*XadT_ z!$MSq^wpW+1gPDxH7V(7V|d2Urw2iC5bC)X>MI;LzR}d5KYRP& z?Vh{Get37!J8MlB?+OFccZoE(tg=r33y4~so~|8*BO%F*t0N0+mX%rb zatj`yJe1;q;wZ%f<@i7^t$QnVAFcZ;bw929ty;b2viu#?2S}sjMj*~kfy@`%VXZ*b zUa|q1@`jS~gp%@dXD+deog7&RE(BQ6=WHzd8{1*aqBpMj|su^J2 zs!^k%)J(<>RIt$wR)Nv>Iyh_d6j=;BDFgM%z+foK*=%aY<}_WBZBIs>G5pvXvORIl zbX1&^B|!RKoY9Awh#A#vRBEc;wg+Mss={Un+Nhp7nSm!}H|%grnU1Q`?dWUJeQ#=;n2EI*q0n;i-3iHYd^ouF$7o7hB zAntSpQ{6FyfG&kO)Rh|jucH5Mmh#lAp>FI*yR7EP5PeJIRL|;MZEBQDPB;eXYxzLva350I=ulw&d4i-E27P|(DZDO&t|8al|?0vG? z2eLld^j2~c!S*-JXGZ*=Mw-u@^8Z0-9%cO7ydz=(MVQAx)FO-<3oWo#*;9c9RM26R zT$HG1B;OQ=(KxFTv%v!89VZ8wb|6i^XSPS2BC)0NgRN z_yfy*(GsvTur}9!GGsB%VWj67b9@_mxv0;;Be8h{BW^n!m$W#(NtGBFKwL5HP!b}* zm=l9L!4}49b`uTLVh~wPfn}Mo3CRGPKvg!-66_#8zaa#N=a0>(CIU68s^jWB@QTgU zRTUMgNf=<_3;ZhCh;+R7W-hqV*m^VlUiT*911EB)se1Gmg#LTNUP^ZtgzkGnucJSo z2|fA7g0Sa4=ux<3J=|Xi_vc5~2Sy6;3y*wqWG#GZBfKYnB(K~azaKvSCF9dA>{uuB$BSG=O z95N6QE%?4k0x+9h6hHfQa~vslacUU|7R#nq4N!NzXGgyOa$V=No^svAKXPR8A83+Q z=NDzi9wPpLUDDUlL7?r{s#VJHT|i2KVS)oNp2JR$rlf4cX}hzxpL&!@%+Gt2X7r* z>m6E)3~v%|-N;R**xa(h{Nh-#rMuYLxqNBqQoesFwca{dXdS%W^82ojx;{StQSW;6 zL;-%SCvJL*Ep022mCLK``To_eytLX|XgL5}!Y#|8rO?XhrTX=-_*q!YpU%r4Ub=PZ zsI%p6uPf zg|kb~5N~6NZQ+Br2Q~>5TOPMzbEuu)yLr^dpV({>_>rw%mUoVe$`q}$eKYVKTT>_K zmTVrryw1!!aidR$5H<-yg?%Wghw