abstract-math 0.0.0.24__tar.gz → 0.0.0.25__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of abstract-math might be problematic. Click here for more details.
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/PKG-INFO +1 -1
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/setup.py +1 -1
- abstract_math-0.0.0.25/src/abstract_math/createflask.py +4 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/flask_scripts/flask_utils.py +1 -1
- abstract_math-0.0.0.25/src/abstract_math/solar_math/main.py +279 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/constants/__init__.py +3 -3
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/constants/distance_constants.py +25 -1
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/constants/planet_constants.py +9 -2
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/constants/time_constants.py +1 -1
- abstract_math-0.0.0.25/src/abstract_math/solar_math/src/utils/escape_velocity.py +111 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/utils/velocity_utils.py +26 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math.egg-info/PKG-INFO +1 -1
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math.egg-info/SOURCES.txt +1 -0
- abstract_math-0.0.0.24/src/abstract_math/solar_math/main.py +0 -263
- abstract_math-0.0.0.24/src/abstract_math/solar_math/src/utils/escape_velocity.py +0 -78
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/README.md +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/pyproject.toml +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/setup.cfg +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/__init__.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/derive_tokens.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/flask_scripts/__init__.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/safe_math.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/__init__.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/flask_utils.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/__init__.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/imports.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/utils/__init__.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/utils/geometry_utils.py +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math.egg-info/dependency_links.txt +0 -0
- {abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math.egg-info/top_level.txt +0 -0
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/flask_scripts/flask_utils.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from abstract_flask import * # must provide Blueprint, request, jsonify, get_request_data, get_logFile, offer_help
|
|
2
2
|
from ..solar_math import *
|
|
3
3
|
# Auto-generated routes
|
|
4
|
-
math_data_bp = Blueprint('math_data_bp', __name__, url_prefix='/utils')
|
|
4
|
+
math_data_bp = Blueprint('math_data_bp', __name__, url_prefix='/utils/')
|
|
5
5
|
logger = get_logFile('math_data_bp')
|
|
6
6
|
|
|
7
7
|
@math_data_bp.route("/normalized_velocity_conversioin", methods=["GET", "POST"], strict_slashes=False)
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# adapt_units_api.py (or wherever you glue this in)
|
|
2
|
+
from typing import *
|
|
3
|
+
from .src.constants.distance_constants import dconvert, _factor as dfactor
|
|
4
|
+
from .src.constants.time_constants import seconds_per
|
|
5
|
+
from .src.constants.planet_constants import planet_radius, get_body, g_at_radius
|
|
6
|
+
from .src.utils.geometry_utils import visible_area_flat, visible_surface_angle
|
|
7
|
+
from .src.utils import get_R_mu,get_normalized_distance,get_normalized_starting_velocity
|
|
8
|
+
from .src.imports import math, mul, div, add # your abstract_math ops
|
|
9
|
+
from .src.constants import (
|
|
10
|
+
DEFAULT_UNITS,
|
|
11
|
+
DEFAULT_TIME,
|
|
12
|
+
DEFAULT_PLANET,
|
|
13
|
+
DEFAULT_START_ALTITUDE,
|
|
14
|
+
DEFAULT_AS_RADIUS
|
|
15
|
+
)
|
|
16
|
+
def normalize_inputs(
|
|
17
|
+
planet: str,
|
|
18
|
+
start_altitude: float,
|
|
19
|
+
starting_velocity: float,
|
|
20
|
+
input_units: str,
|
|
21
|
+
input_time: str,
|
|
22
|
+
target_distance: float = None,
|
|
23
|
+
) -> dict:
|
|
24
|
+
"""Normalize input altitudes and velocities into SI (meters, seconds)."""
|
|
25
|
+
start_alt_m = get_normalized_distance(start_altitude, input_units)
|
|
26
|
+
target_alt_m = get_normalized_distance(target_distance, input_units)
|
|
27
|
+
|
|
28
|
+
v0_mps = get_normalized_starting_velocity(
|
|
29
|
+
start_altitude=start_alt_m,
|
|
30
|
+
starting_velocity=starting_velocity,
|
|
31
|
+
input_units=input_units,
|
|
32
|
+
input_time=input_time,
|
|
33
|
+
planet=planet,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
"start_alt_m": start_alt_m,
|
|
38
|
+
"target_alt_m": target_alt_m,
|
|
39
|
+
"v0_mps": v0_mps,
|
|
40
|
+
}
|
|
41
|
+
# --- Analyzer (prints a scan; no blocking input) ---
|
|
42
|
+
def analyze_visible_surface(
|
|
43
|
+
altitude_step: float = 200.0,
|
|
44
|
+
max_steps: int = 20,
|
|
45
|
+
fov_range: tuple[int, int] = (20, 160),
|
|
46
|
+
fov_interval: int = 10,
|
|
47
|
+
input_units: str = DEFAULT_UNITS, # how to interpret altitude numbers
|
|
48
|
+
display_units: str = DEFAULT_UNITS, # how to print areas/radii
|
|
49
|
+
planet: str = DEFAULT_PLANET,
|
|
50
|
+
printit: bool = False
|
|
51
|
+
):
|
|
52
|
+
"""
|
|
53
|
+
Scan altitudes/FOVs. Altitudes are interpreted in `input_units`.
|
|
54
|
+
Results are printed in `display_units`.
|
|
55
|
+
"""
|
|
56
|
+
# Planet radius and full area (compute in meters, convert for display)
|
|
57
|
+
r_m = planet_radius(planet, DEFAULT_UNITS)
|
|
58
|
+
full_area_m2 = 4.0 * math.pi * (r_m ** 2)
|
|
59
|
+
k_disp = dfactor(DEFAULT_UNITS, display_units) # linear meter->display factor
|
|
60
|
+
full_area_disp = full_area_m2 * (k_disp ** 2) # convert area to display units^2
|
|
61
|
+
|
|
62
|
+
all_stats = {"output": "", "input_units": input_units,
|
|
63
|
+
"display_units": display_units, "vars": []}
|
|
64
|
+
|
|
65
|
+
for i in range(1, max_steps + 1):
|
|
66
|
+
all_stats["vars"].append({})
|
|
67
|
+
altitude_in = altitude_step * i # input_units
|
|
68
|
+
altitude_m = dconvert(altitude_in, input_units, DEFAULT_UNITS)
|
|
69
|
+
|
|
70
|
+
all_stats["vars"][-1]['altitude_input'] = altitude_in
|
|
71
|
+
all_stats["vars"][-1]['input_units'] = input_units
|
|
72
|
+
all_stats["vars"][-1]['fov'] = []
|
|
73
|
+
|
|
74
|
+
alt_pretty = dconvert(altitude_in, input_units, display_units)
|
|
75
|
+
all_stats["output"] += (
|
|
76
|
+
f"\n=== Altitude: {altitude_in} {input_units} (≈ {alt_pretty:.3f} {display_units}) ===\n"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
for fov in range(fov_range[0], fov_range[1] + 1, fov_interval):
|
|
80
|
+
# Compute visible area/radius in meters, convert to display units
|
|
81
|
+
area_m2, vis_radius_m = visible_area_flat(fov, altitude_m, DEFAULT_UNITS)
|
|
82
|
+
area_disp = area_m2 * (k_disp ** 2)
|
|
83
|
+
vis_radius_disp = dconvert(vis_radius_m, DEFAULT_UNITS, display_units)
|
|
84
|
+
|
|
85
|
+
# Span uses geometry only; r_m is in meters
|
|
86
|
+
_, angle_deg = visible_surface_angle(vis_radius_m, r_m)
|
|
87
|
+
|
|
88
|
+
coverage_pct = 100.0 * (area_disp / full_area_disp)
|
|
89
|
+
|
|
90
|
+
fov_output = (
|
|
91
|
+
f"FOV: {fov:>3}° | "
|
|
92
|
+
f"Area: {area_disp:>12.2f} {display_units}² | "
|
|
93
|
+
f"Span: {angle_deg:>7.2f}° | "
|
|
94
|
+
f"Flat-visible: {coverage_pct:>6.3f}% | "
|
|
95
|
+
f"visR≈{vis_radius_disp:.3f} {display_units}"
|
|
96
|
+
)
|
|
97
|
+
all_stats["output"] += fov_output + "\n"
|
|
98
|
+
|
|
99
|
+
all_stats["vars"][-1]['fov'].append({
|
|
100
|
+
"FOV": fov,
|
|
101
|
+
"area": area_disp,
|
|
102
|
+
"angle_deg": angle_deg,
|
|
103
|
+
"coverage_pct": coverage_pct,
|
|
104
|
+
"visible_radius": vis_radius_disp,
|
|
105
|
+
"output": fov_output
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
if printit:
|
|
109
|
+
print(all_stats.get('output'))
|
|
110
|
+
return all_stats
|
|
111
|
+
# --- core integrator step ---
|
|
112
|
+
def calculate_avrt(mu, v, r, t=0.0, dt_s=1.0, steps=0):
|
|
113
|
+
"""Single Euler step update for radial motion."""
|
|
114
|
+
a = - div(mu, mul(r, r)) # inward accel
|
|
115
|
+
v = add(v, mul(a, dt_s))
|
|
116
|
+
r = add(r, mul(v, dt_s))
|
|
117
|
+
t = add(t, dt_s)
|
|
118
|
+
steps += 1
|
|
119
|
+
return v, r, t, steps
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# --- tracker helper ---
|
|
123
|
+
def init_tracker(r0: float) -> dict:
|
|
124
|
+
"""Initialize stats tracker."""
|
|
125
|
+
return {
|
|
126
|
+
"furthest_r": r0,
|
|
127
|
+
"time_at_furthest": 0.0,
|
|
128
|
+
"furthest_step": 0,
|
|
129
|
+
"total_distance": 0.0,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# --- SI integrator with tracking ---
|
|
134
|
+
def simulate_radial_flight_si(
|
|
135
|
+
v0_mps: float,
|
|
136
|
+
start_alt_m: float,
|
|
137
|
+
planet: str,
|
|
138
|
+
dt_s: float = 1.0,
|
|
139
|
+
max_steps: int = 5_000_000,
|
|
140
|
+
target_alt_m: float = None
|
|
141
|
+
) -> dict:
|
|
142
|
+
"""Forward-Euler radial integrator, SI only (meters/seconds)."""
|
|
143
|
+
R, mu = get_R_mu(planet=planet)
|
|
144
|
+
r0 = add(R, start_alt_m)
|
|
145
|
+
r = r0
|
|
146
|
+
v = v0_mps
|
|
147
|
+
t = 0.0
|
|
148
|
+
prev_r = r0
|
|
149
|
+
r_target = add(R, target_alt_m) if target_alt_m else float("inf")
|
|
150
|
+
traveled_m = 0.0
|
|
151
|
+
|
|
152
|
+
hit_surface, hit_target, turned_back = False, False, False
|
|
153
|
+
steps = 0
|
|
154
|
+
tracker = init_tracker(r0)
|
|
155
|
+
|
|
156
|
+
for _ in range(max_steps):
|
|
157
|
+
if r <= R:
|
|
158
|
+
hit_surface = True
|
|
159
|
+
break
|
|
160
|
+
if target_alt_m and r >= r_target:
|
|
161
|
+
hit_target = True
|
|
162
|
+
break
|
|
163
|
+
|
|
164
|
+
v, r, t, steps = calculate_avrt(mu, v, r, t, dt_s, steps)
|
|
165
|
+
|
|
166
|
+
# update traveled distance
|
|
167
|
+
traveled_step = abs(r - prev_r)
|
|
168
|
+
traveled_m += traveled_step
|
|
169
|
+
tracker["total_distance"] += traveled_step
|
|
170
|
+
prev_r = r
|
|
171
|
+
|
|
172
|
+
# update furthest distance tracker
|
|
173
|
+
if r > tracker["furthest_r"]:
|
|
174
|
+
tracker["furthest_r"] = r
|
|
175
|
+
tracker["time_at_furthest"] = t
|
|
176
|
+
tracker["furthest_step"] = steps
|
|
177
|
+
|
|
178
|
+
# detect turnaround
|
|
179
|
+
if not target_alt_m and v < 0 and r < r0:
|
|
180
|
+
turned_back = True
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
altitude_m = max(0.0, r - R)
|
|
184
|
+
g_end = g_at_radius(mu, r)
|
|
185
|
+
g_surface = g_at_radius(mu, R)
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
"ok": True,
|
|
189
|
+
"planet": planet,
|
|
190
|
+
"r_m": r,
|
|
191
|
+
"altitude_m": altitude_m,
|
|
192
|
+
"vEnd_mps": v,
|
|
193
|
+
"time_s": t,
|
|
194
|
+
"g_end_mps2": g_end,
|
|
195
|
+
"g_ratio_surface": div(g_end, g_surface),
|
|
196
|
+
"steps": steps,
|
|
197
|
+
"hit_surface": hit_surface,
|
|
198
|
+
"hit_target": hit_target,
|
|
199
|
+
"turned_back": turned_back,
|
|
200
|
+
"traveled_m": traveled_m,
|
|
201
|
+
"vesc_end_mps": math.sqrt(mul(2.0, div(mu, r))),
|
|
202
|
+
|
|
203
|
+
# extended stats
|
|
204
|
+
"furthest_r": tracker["furthest_r"],
|
|
205
|
+
"furthest_altitude_m": tracker["furthest_r"] - R,
|
|
206
|
+
"time_at_furthest": tracker["time_at_furthest"],
|
|
207
|
+
"total_distance_m": tracker["total_distance"],
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# --- wrapper with unit conversions ---
|
|
212
|
+
def radial_travel(
|
|
213
|
+
starting_velocity: float = None,
|
|
214
|
+
start_altitude: float = None,
|
|
215
|
+
input_units: str = DEFAULT_UNITS,
|
|
216
|
+
input_time: str = DEFAULT_TIME,
|
|
217
|
+
output_units: str = DEFAULT_UNITS,
|
|
218
|
+
output_time: str = DEFAULT_TIME,
|
|
219
|
+
*,
|
|
220
|
+
planet: str = DEFAULT_PLANET,
|
|
221
|
+
dt_s: float = 1.0,
|
|
222
|
+
max_steps: int = 5_000_000,
|
|
223
|
+
target_distance: float = None
|
|
224
|
+
) -> dict:
|
|
225
|
+
"""Wrapper: handles units, runs SI integrator, converts outputs."""
|
|
226
|
+
norm = normalize_inputs(
|
|
227
|
+
planet=planet, start_altitude=start_altitude, starting_velocity=starting_velocity,
|
|
228
|
+
input_units=input_units, input_time=input_time, target_distance=target_distance
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
sim = simulate_radial_flight_si(
|
|
232
|
+
v0_mps=norm["v0_mps"],
|
|
233
|
+
start_alt_m=norm["start_alt_m"],
|
|
234
|
+
planet=planet,
|
|
235
|
+
dt_s=dt_s,
|
|
236
|
+
max_steps=max_steps,
|
|
237
|
+
target_alt_m=norm["target_alt_m"],
|
|
238
|
+
)
|
|
239
|
+
if not sim.get("ok"):
|
|
240
|
+
return sim
|
|
241
|
+
|
|
242
|
+
# Output conversions
|
|
243
|
+
sec_per_out = seconds_per(output_time)
|
|
244
|
+
conv = lambda m: dconvert(m, DEFAULT_UNITS, output_units)
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
"ok": True,
|
|
248
|
+
"planet": planet,
|
|
249
|
+
"inputs": {
|
|
250
|
+
"start_altitude": start_altitude,
|
|
251
|
+
"starting_velocity": starting_velocity,
|
|
252
|
+
"input_units": input_units,
|
|
253
|
+
"input_time": input_time,
|
|
254
|
+
"output_units": output_units,
|
|
255
|
+
"output_time": output_time,
|
|
256
|
+
"target_distance": target_distance,
|
|
257
|
+
},
|
|
258
|
+
# final state
|
|
259
|
+
"altitude": conv(sim["altitude_m"]),
|
|
260
|
+
"radius_from_center": conv(sim["r_m"]),
|
|
261
|
+
"distance_traveled": conv(sim["traveled_m"]),
|
|
262
|
+
"velocity": mul(dconvert(sim["vEnd_mps"], DEFAULT_UNITS, output_units), sec_per_out),
|
|
263
|
+
"velocity_escape_end": mul(dconvert(sim["vesc_end_mps"], DEFAULT_UNITS, output_units), sec_per_out),
|
|
264
|
+
"time": div(sim["time_s"], sec_per_out),
|
|
265
|
+
"time_unit": output_time,
|
|
266
|
+
"g_end_mps2": sim["g_end_mps2"],
|
|
267
|
+
"g_ratio_surface": sim["g_ratio_surface"],
|
|
268
|
+
"steps": sim["steps"],
|
|
269
|
+
"hit_surface": sim["hit_surface"],
|
|
270
|
+
"hit_target": sim["hit_target"],
|
|
271
|
+
"turned_back": sim["turned_back"],
|
|
272
|
+
|
|
273
|
+
# extended stats (converted)
|
|
274
|
+
"furthest_distance": conv(sim["furthest_altitude_m"]),
|
|
275
|
+
"furthest_radius": conv(sim["furthest_r"]),
|
|
276
|
+
"time_at_furthest": div(sim["time_at_furthest"], sec_per_out),
|
|
277
|
+
"total_distance": conv(sim["total_distance_m"]),
|
|
278
|
+
}
|
|
279
|
+
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
from .distance_constants import (
|
|
3
3
|
DISTANCE_CONVERSIONS, ALL_DISTANCE_UNITS,
|
|
4
4
|
normalize_distance_unit, get_distance_unit_conversions,
|
|
5
|
-
_factor,
|
|
5
|
+
_factor, dconvert,DEFAULT_UNITS,DEFAULT_START_ALTITUDE
|
|
6
6
|
)
|
|
7
7
|
from .time_constants import (
|
|
8
8
|
TIME_CONVERSIONS, ALL_TIME_UNITS,
|
|
9
9
|
normalize_time_unit, get_time_unit_conversions,
|
|
10
|
-
time_factor, convert_time, seconds_per,
|
|
10
|
+
time_factor, convert_time, seconds_per,DEFAULT_TIME
|
|
11
11
|
)
|
|
12
12
|
from .planet_constants import (
|
|
13
13
|
PLANETS, G, g0, MU_MOON,
|
|
@@ -15,5 +15,5 @@ from .planet_constants import (
|
|
|
15
15
|
full_planet_surface_area, planet_volume, planet_circumference,
|
|
16
16
|
planet_mass, planet_surface_g, escape_velocity,
|
|
17
17
|
earth_radius, earth_diameter, full_earth_surface_area,
|
|
18
|
-
earth_volume, earth_circumference,
|
|
18
|
+
earth_volume, earth_circumference,DEFAULT_PLANET,DEFAULT_AS_RADIUS
|
|
19
19
|
)
|
|
@@ -19,6 +19,8 @@ DISTANCE_CONVERSIONS: Dict[str, Dict[str, Dict[str, float]]] = {
|
|
|
19
19
|
"feet": FEET
|
|
20
20
|
}
|
|
21
21
|
ALL_DISTANCE_UNITS = ("meters", "kilometers", "miles", "feet")
|
|
22
|
+
DEFAULT_UNITS="meters"
|
|
23
|
+
DEFAULT_START_ALTITUDE=0.0
|
|
22
24
|
# -------------------------
|
|
23
25
|
# Unit helpers
|
|
24
26
|
# -------------------------
|
|
@@ -41,5 +43,27 @@ def _factor(unit_from: str, unit_to: str) -> float:
|
|
|
41
43
|
ut = get_distance_unit_conversions(unit_to)["conv"]["meters"] # meters per 1 to-unit
|
|
42
44
|
return div(uf, ut)
|
|
43
45
|
|
|
44
|
-
def
|
|
46
|
+
def dconvert(value: float, unit_from: str, unit_to: str) -> float:
|
|
45
47
|
return mul(value, _factor(unit_from, unit_to))
|
|
48
|
+
def get_normalized_distance(
|
|
49
|
+
distance: Optional[float] = None,
|
|
50
|
+
input_units: str = DEFAULT_UNITS
|
|
51
|
+
):
|
|
52
|
+
distance = target_alt_m = distance or 0
|
|
53
|
+
if distance is not None:
|
|
54
|
+
target_alt_m = dconvert(value=distance,
|
|
55
|
+
unit_from=input_units,
|
|
56
|
+
unit_to=DEFAULT_UNITS
|
|
57
|
+
)
|
|
58
|
+
return target_alt_m
|
|
59
|
+
def get_target_distance(
|
|
60
|
+
distance: Optional[float] = None,
|
|
61
|
+
input_units: str = DEFAULT_UNITS,
|
|
62
|
+
output_units: str = DEFAULT_UNITS,
|
|
63
|
+
):
|
|
64
|
+
distance = target_distance = distance or 0
|
|
65
|
+
if distance is not None:
|
|
66
|
+
target_distance = dconvert(value=distance,
|
|
67
|
+
unit_from=input_units,
|
|
68
|
+
unit_to=output_units)
|
|
69
|
+
return target_distance
|
|
@@ -28,7 +28,8 @@ PLANETS = [
|
|
|
28
28
|
{ "name":'Neptune',"m0_deg":-55.12002969,"mu":6.83653e15,"a":4.4983964e12,"e":0.00859048,"radiusPx":10,"color":'#4363d8',"radius":24764000,"escapeVel":23500,"n":8,"peri_lon_deg":44.96476227 },
|
|
29
29
|
{ "name":'Moon',"m0_deg":0,"mu":MU_MOON,"a":3.844e8,"e":0.0549,"radiusPx":5,"color":'lightgray',"radius":1.737e6,"escapeVel":2380,"n":9}
|
|
30
30
|
]
|
|
31
|
-
|
|
31
|
+
DEFAULT_PLANET='earth'
|
|
32
|
+
DEFAULT_AS_RADIUS=False
|
|
32
33
|
# -------------------------
|
|
33
34
|
# Body enrichment + lookup
|
|
34
35
|
# -------------------------
|
|
@@ -46,7 +47,7 @@ def _enrich_body(b: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
46
47
|
|
|
47
48
|
_NAME_ALIASES = {"sol": "sun", "terra": "earth", "luna": "moon"}
|
|
48
49
|
def _normalize_name(name: str) -> str:
|
|
49
|
-
n = name.
|
|
50
|
+
n = name.lower()
|
|
50
51
|
return _NAME_ALIASES.get(n, n)
|
|
51
52
|
|
|
52
53
|
_BODY_BY_NAME: Dict[str, Dict[str, Any]] = {}
|
|
@@ -154,3 +155,9 @@ def get_body(planet: str) -> Dict[str, Any]:
|
|
|
154
155
|
|
|
155
156
|
def g_at_radius(mu: float, r_m: float) -> float:
|
|
156
157
|
return div(mu, mul(r_m, r_m))
|
|
158
|
+
|
|
159
|
+
def get_R_mu(planet: str = DEFAULT_PLANET):
|
|
160
|
+
body = get_body(planet)
|
|
161
|
+
mu = body.get("mu") # m^3/s^2
|
|
162
|
+
R = body.get("radius") # m
|
|
163
|
+
return R,mu
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# src/utils/escape_velocity.py
|
|
2
|
+
from ..imports import math, mul, div, add
|
|
3
|
+
from ..constants import (
|
|
4
|
+
DEFAULT_UNITS,
|
|
5
|
+
DEFAULT_TIME,
|
|
6
|
+
DEFAULT_PLANET,
|
|
7
|
+
DEFAULT_START_ALTITUDE,
|
|
8
|
+
DEFAULT_AS_RADIUS
|
|
9
|
+
)
|
|
10
|
+
from ..constants.planet_constants import get_body,get_R_mu
|
|
11
|
+
from ..constants.distance_constants import dconvert,get_target_distance,get_normalized_distance
|
|
12
|
+
from ..constants.time_constants import get_time_unit_conversions, normalize_time_unit, seconds_per
|
|
13
|
+
from .velocity_utils import normalized_velocity_conversioin
|
|
14
|
+
def get_r_m(planet: str = DEFAULT_PLANET,start_altitude: float = DEFAULT_START_ALTITUDE,input_units: str = DEFAULT_UNITS,as_radius:bool = DEFAULT_AS_RADIUS):
|
|
15
|
+
R,mu = get_R_mu(planet=planet)
|
|
16
|
+
r_m = dconvert(start_altitude, input_units, DEFAULT_UNITS)
|
|
17
|
+
# Determine radius from center in meters
|
|
18
|
+
if not as_radius:
|
|
19
|
+
r_m = add(R, r_m)
|
|
20
|
+
if r_m <= 0:
|
|
21
|
+
return {"ok": False, "error": "computed radius is non-positive"}
|
|
22
|
+
return r_m
|
|
23
|
+
def get_vesc_mps(
|
|
24
|
+
planet: str = DEFAULT_PLANET,
|
|
25
|
+
start_altitude: float = DEFAULT_START_ALTITUDE,
|
|
26
|
+
input_units: str = DEFAULT_UNITS,
|
|
27
|
+
as_radius:bool = DEFAULT_AS_RADIUS
|
|
28
|
+
):
|
|
29
|
+
R,mu = get_R_mu(planet=planet)
|
|
30
|
+
r_m = get_r_m(planet=planet,start_altitude=start_altitude,input_units=input_units,as_radius=as_radius)
|
|
31
|
+
vesc_mps = math.sqrt(mul(2.0, div(mu, r_m)))
|
|
32
|
+
return vesc_mps
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_normalized_starting_velocity(
|
|
37
|
+
start_altitude: float = None,
|
|
38
|
+
starting_velocity: float = None,
|
|
39
|
+
input_units: str = DEFAULT_UNITS, # distance part of starting_velocity & start_distance
|
|
40
|
+
input_time: str = DEFAULT_TIME, # time part of starting_velocity
|
|
41
|
+
output_units: str = DEFAULT_UNITS,
|
|
42
|
+
output_time: str = DEFAULT_TIME,
|
|
43
|
+
planet: str = DEFAULT_PLANET
|
|
44
|
+
):
|
|
45
|
+
start_altitude = start_altitude or 0
|
|
46
|
+
if starting_velocity == None:
|
|
47
|
+
starting_velocity = escape_velocity_at(planet=planet,
|
|
48
|
+
start_altitude=start_altitude,
|
|
49
|
+
input_time=input_time,
|
|
50
|
+
input_units=input_units,
|
|
51
|
+
output_time=input_time,
|
|
52
|
+
output_units=input_units
|
|
53
|
+
)
|
|
54
|
+
return normalized_velocity_conversioin(
|
|
55
|
+
velocity=starting_velocity,
|
|
56
|
+
input_time=input_time,
|
|
57
|
+
input_units=input_units
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
def escape_velocity_at(
|
|
61
|
+
planet: str = DEFAULT_PLANET,
|
|
62
|
+
start_altitude: float = DEFAULT_START_ALTITUDE,
|
|
63
|
+
*,
|
|
64
|
+
input_time: str = DEFAULT_TIME, # how to interpret `distance`
|
|
65
|
+
input_units: str = DEFAULT_UNITS, # how to interpret `distance`
|
|
66
|
+
output_units: str = DEFAULT_UNITS, # distance unit for the *speed*
|
|
67
|
+
output_time: str = DEFAULT_TIME, # time unit for the *speed*
|
|
68
|
+
as_radius: bool = DEFAULT_AS_RADIUS # False => `distance` is altitude above surface; True => radius from center
|
|
69
|
+
) -> dict:
|
|
70
|
+
"""
|
|
71
|
+
Compute v_escape at a given location around `planet`.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
planet: body name (must exist in PLANETS)
|
|
75
|
+
start_altitude: if as_radius=False => altitude above surface; if as_radius=True => radius from center
|
|
76
|
+
input_units: units of `distance`
|
|
77
|
+
output_units: distance unit of the returned speed
|
|
78
|
+
output_time: time unit of the returned speed ('s'|'min'|'h' etc.)
|
|
79
|
+
as_radius: interpret `distance` as radius-from-center when True
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
{
|
|
83
|
+
"ok": True,
|
|
84
|
+
"planet": str,
|
|
85
|
+
"radius_from_center": <float in output_units>,
|
|
86
|
+
"v_escape": <float in output_units/output_time>,
|
|
87
|
+
"v_escape_mps": <float in m/s>,
|
|
88
|
+
"units": {"distance": output_units, "time": output_time}
|
|
89
|
+
}
|
|
90
|
+
"""
|
|
91
|
+
if not (isinstance(start_altitude, (int, float)) and math.isfinite(start_altitude) and start_altitude >= 0):
|
|
92
|
+
return {"ok": False, "error": "distance must be a non-negative number"}
|
|
93
|
+
R,mu = get_R_mu(planet=planet)
|
|
94
|
+
# v_esc (m/s)
|
|
95
|
+
r_m = get_r_m(planet=planet,start_altitude=start_altitude,input_units=input_units,as_radius=as_radius)
|
|
96
|
+
vesc_mps = get_vesc_mps(planet=planet,start_altitude=start_altitude,input_units=input_units,as_radius=as_radius)
|
|
97
|
+
# Convert speed to <output_units>/<output_time>
|
|
98
|
+
vesc_units_per_time = dconvert(vesc_mps, DEFAULT_UNITS, output_units)
|
|
99
|
+
time_per = seconds_per(output_time) # seconds per 1 output_time
|
|
100
|
+
vesc_out = mul(vesc_units_per_time, time_per) # <output_units>/<output_time>
|
|
101
|
+
# Also return the radius in output_units for convenience
|
|
102
|
+
r_out = dconvert(r_m, DEFAULT_UNITS, output_units)
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
"ok": True,
|
|
106
|
+
"planet": planet,
|
|
107
|
+
"radius_from_center": r_out,
|
|
108
|
+
"v_escape": vesc_out,
|
|
109
|
+
"v_escape_mps": vesc_mps,
|
|
110
|
+
"units": {"distance": output_units, "time": output_time}
|
|
111
|
+
}
|
|
@@ -24,3 +24,29 @@ def mps_to_distance_per_time(v_mps: float, dist_units: str, time_units: str) ->
|
|
|
24
24
|
v_units_per_sec = div(v_mps, meters_per_unit) # [dist_units / s]
|
|
25
25
|
sec_per_time = seconds_per(time_units)
|
|
26
26
|
return mul(v_units_per_sec, sec_per_time) # [dist_units / time_units]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_velocity_conversioin(
|
|
32
|
+
velocity,
|
|
33
|
+
input_time: str = DEFAULT_TIME,
|
|
34
|
+
input_units: str = DEFAULT_UNITS,
|
|
35
|
+
output_units: str = DEFAULT_UNITS,
|
|
36
|
+
output_time: str = DEFAULT_TIME,
|
|
37
|
+
):
|
|
38
|
+
v0_mps = distance_per_time_to_mps(v=velocity, dist_units=input_units, time_units=input_time)
|
|
39
|
+
v0_unit_p_time = mps_to_distance_per_time(v_mps=v0_mps, dist_units=output_units, time_units=output_time)
|
|
40
|
+
return v0_unit_p_time
|
|
41
|
+
|
|
42
|
+
def normalized_velocity_conversioin(
|
|
43
|
+
velocity,
|
|
44
|
+
input_time: str = DEFAULT_TIME,
|
|
45
|
+
input_units: str = DEFAULT_UNITS
|
|
46
|
+
):
|
|
47
|
+
v0_mps = get_velocity_conversioin(
|
|
48
|
+
velocity=velocity,
|
|
49
|
+
input_time=input_time,
|
|
50
|
+
input_units=input_units
|
|
51
|
+
)
|
|
52
|
+
return v0_mps
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
# adapt_units_api.py (or wherever you glue this in)
|
|
2
|
-
from typing import *
|
|
3
|
-
from .src.constants.distance_constants import convert as dconvert, _factor as dfactor
|
|
4
|
-
from .src.constants.time_constants import seconds_per
|
|
5
|
-
from .src.constants.planet_constants import planet_radius, get_body, g_at_radius
|
|
6
|
-
from .src.utils.geometry_utils import visible_area_flat, visible_surface_angle
|
|
7
|
-
from .src.imports import math, mul, div, add # your abstract_math ops
|
|
8
|
-
def normalized_velocity_conversioin(starting_velocity, input_time, input_units):
|
|
9
|
-
sec_per_time = seconds_per(input_time) # sec / timeunit
|
|
10
|
-
v_units_per_sec = div(starting_velocity, sec_per_time) # <input_units> / s
|
|
11
|
-
v0_mps = dconvert(v_units_per_sec, input_units, "meters") # m / s
|
|
12
|
-
return v0_mps
|
|
13
|
-
|
|
14
|
-
# --- Analyzer (prints a scan; no blocking input) ---
|
|
15
|
-
def analyze_visible_surface(
|
|
16
|
-
altitude_step: float = 200.0,
|
|
17
|
-
max_steps: int = 20,
|
|
18
|
-
fov_range: tuple[int, int] = (20, 160),
|
|
19
|
-
fov_interval: int = 10,
|
|
20
|
-
input_units: str = 'meters', # how to interpret altitude numbers
|
|
21
|
-
display_units: str = 'meters', # how to print areas/radii
|
|
22
|
-
planet: str = 'earth',
|
|
23
|
-
printit: bool = False
|
|
24
|
-
):
|
|
25
|
-
"""
|
|
26
|
-
Scan altitudes/FOVs. Altitudes are interpreted in `input_units`.
|
|
27
|
-
Results are printed in `display_units`.
|
|
28
|
-
"""
|
|
29
|
-
# Planet radius and full area (compute in meters, convert for display)
|
|
30
|
-
r_m = planet_radius(planet, 'meters')
|
|
31
|
-
full_area_m2 = 4.0 * math.pi * (r_m ** 2)
|
|
32
|
-
k_disp = dfactor('meters', display_units) # linear meter->display factor
|
|
33
|
-
full_area_disp = full_area_m2 * (k_disp ** 2) # convert area to display units^2
|
|
34
|
-
|
|
35
|
-
all_stats = {"output": "", "input_units": input_units,
|
|
36
|
-
"display_units": display_units, "vars": []}
|
|
37
|
-
|
|
38
|
-
for i in range(1, max_steps + 1):
|
|
39
|
-
all_stats["vars"].append({})
|
|
40
|
-
altitude_in = altitude_step * i # input_units
|
|
41
|
-
altitude_m = dconvert(altitude_in, input_units, 'meters')
|
|
42
|
-
|
|
43
|
-
all_stats["vars"][-1]['altitude_input'] = altitude_in
|
|
44
|
-
all_stats["vars"][-1]['input_units'] = input_units
|
|
45
|
-
all_stats["vars"][-1]['fov'] = []
|
|
46
|
-
|
|
47
|
-
alt_pretty = dconvert(altitude_in, input_units, display_units)
|
|
48
|
-
all_stats["output"] += (
|
|
49
|
-
f"\n=== Altitude: {altitude_in} {input_units} (≈ {alt_pretty:.3f} {display_units}) ===\n"
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
for fov in range(fov_range[0], fov_range[1] + 1, fov_interval):
|
|
53
|
-
# Compute visible area/radius in meters, convert to display units
|
|
54
|
-
area_m2, vis_radius_m = visible_area_flat(fov, altitude_m, 'meters')
|
|
55
|
-
area_disp = area_m2 * (k_disp ** 2)
|
|
56
|
-
vis_radius_disp = dconvert(vis_radius_m, 'meters', display_units)
|
|
57
|
-
|
|
58
|
-
# Span uses geometry only; r_m is in meters
|
|
59
|
-
_, angle_deg = visible_surface_angle(vis_radius_m, r_m)
|
|
60
|
-
|
|
61
|
-
coverage_pct = 100.0 * (area_disp / full_area_disp)
|
|
62
|
-
|
|
63
|
-
fov_output = (
|
|
64
|
-
f"FOV: {fov:>3}° | "
|
|
65
|
-
f"Area: {area_disp:>12.2f} {display_units}² | "
|
|
66
|
-
f"Span: {angle_deg:>7.2f}° | "
|
|
67
|
-
f"Flat-visible: {coverage_pct:>6.3f}% | "
|
|
68
|
-
f"visR≈{vis_radius_disp:.3f} {display_units}"
|
|
69
|
-
)
|
|
70
|
-
all_stats["output"] += fov_output + "\n"
|
|
71
|
-
|
|
72
|
-
all_stats["vars"][-1]['fov'].append({
|
|
73
|
-
"FOV": fov,
|
|
74
|
-
"area": area_disp,
|
|
75
|
-
"angle_deg": angle_deg,
|
|
76
|
-
"coverage_pct": coverage_pct,
|
|
77
|
-
"visible_radius": vis_radius_disp,
|
|
78
|
-
"output": fov_output
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
if printit:
|
|
82
|
-
print(all_stats.get('output'))
|
|
83
|
-
return all_stats
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def simulate_radial_flight(
|
|
87
|
-
planet: str,
|
|
88
|
-
start_altitude: float,
|
|
89
|
-
start_units: str,
|
|
90
|
-
v0_mps: float,
|
|
91
|
-
dt_s: float = 1.0,
|
|
92
|
-
max_steps: int = 5_000_000,
|
|
93
|
-
target_altitude_m: Optional[float] = None
|
|
94
|
-
) -> dict:
|
|
95
|
-
"""
|
|
96
|
-
Forward-Euler radial integrator (toy model).
|
|
97
|
-
Returns a dict with SI (meters, seconds) internal results.
|
|
98
|
-
"""
|
|
99
|
-
if not (isinstance(start_altitude, (int, float)) and start_altitude >= 0):
|
|
100
|
-
return {"ok": False, "error": "Invalid start_altitude", "steps": 0}
|
|
101
|
-
if not (isinstance(v0_mps, (int, float)) and math.isfinite(v0_mps)):
|
|
102
|
-
return {"ok": False, "error": "Invalid starting_velocity (after unit conversion)", "steps": 0}
|
|
103
|
-
if not (dt_s > 0):
|
|
104
|
-
return {"ok": False, "error": "dt_s must be > 0", "steps": 0}
|
|
105
|
-
|
|
106
|
-
body = get_body(planet)
|
|
107
|
-
mu = body["mu"]
|
|
108
|
-
R = body["radius"]
|
|
109
|
-
|
|
110
|
-
r0 = add(R, dconvert(start_altitude, start_units, "meters"))
|
|
111
|
-
r = r0
|
|
112
|
-
v = v0_mps # outward positive, m/s
|
|
113
|
-
t = 0.0
|
|
114
|
-
|
|
115
|
-
has_target = target_altitude_m is not None and target_altitude_m > 0
|
|
116
|
-
r_target = add(R, target_altitude_m if has_target else float("inf"))
|
|
117
|
-
|
|
118
|
-
hit_surface = False
|
|
119
|
-
hit_target = False
|
|
120
|
-
turned_back_below_start = False
|
|
121
|
-
|
|
122
|
-
steps = 0
|
|
123
|
-
for _ in range(max_steps):
|
|
124
|
-
if r <= R:
|
|
125
|
-
hit_surface = True
|
|
126
|
-
break
|
|
127
|
-
if has_target and r >= r_target:
|
|
128
|
-
hit_target = True
|
|
129
|
-
break
|
|
130
|
-
|
|
131
|
-
a = - div(mu, mul(r, r)) # inward
|
|
132
|
-
v = add(v, mul(a, dt_s))
|
|
133
|
-
r = add(r, mul(v, dt_s))
|
|
134
|
-
t = add(t, dt_s)
|
|
135
|
-
steps += 1
|
|
136
|
-
|
|
137
|
-
if (not has_target) and (v < 0) and (r < r0):
|
|
138
|
-
turned_back_below_start = True
|
|
139
|
-
break
|
|
140
|
-
|
|
141
|
-
altitude_m = max(0.0, r - R)
|
|
142
|
-
g_end = g_at_radius(mu, r)
|
|
143
|
-
g_surface = g_at_radius(mu, R)
|
|
144
|
-
traveled_m = max(0.0, altitude_m - (r0 - R))
|
|
145
|
-
|
|
146
|
-
return {
|
|
147
|
-
"ok": True,
|
|
148
|
-
"planet": planet,
|
|
149
|
-
"rFromCenter_m": r,
|
|
150
|
-
"altitude_m": altitude_m,
|
|
151
|
-
"vEnd_mps": v,
|
|
152
|
-
"time_s": t,
|
|
153
|
-
"gAtEnd_mps2": g_end,
|
|
154
|
-
"gRatioSurface": div(g_end, g_surface),
|
|
155
|
-
"steps": steps,
|
|
156
|
-
"hitSurface": hit_surface,
|
|
157
|
-
"hitTarget": hit_target,
|
|
158
|
-
"turnedBackBelowStart": turned_back_below_start,
|
|
159
|
-
"traveled_m": traveled_m,
|
|
160
|
-
"vEsc_end_mps": math.sqrt(mul(2.0, div(mu, r))),
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def radial_travel(
|
|
165
|
-
start_distance: float,
|
|
166
|
-
starting_velocity: float,
|
|
167
|
-
input_units: str = "meters", # distance part of starting_velocity & start_distance
|
|
168
|
-
input_time: str = "s", # time part of starting_velocity
|
|
169
|
-
output_units: str = "meters",
|
|
170
|
-
output_time: str = "s",
|
|
171
|
-
planet: str = "earth",
|
|
172
|
-
*,
|
|
173
|
-
dt_s: float = 1.0,
|
|
174
|
-
max_steps: int = 5_000_000,
|
|
175
|
-
target_distance: Optional[float] = None # in input_units above surface
|
|
176
|
-
) -> dict:
|
|
177
|
-
"""
|
|
178
|
-
Single-call wrapper:
|
|
179
|
-
|
|
180
|
-
- start_distance: altitude above surface (input_units)
|
|
181
|
-
- starting_velocity: <input_units>/<input_time>
|
|
182
|
-
"""
|
|
183
|
-
|
|
184
|
-
v0_mps = normalized_velocity_conversioin(starting_velocity, input_time, input_units)
|
|
185
|
-
|
|
186
|
-
# Optional target altitude (to meters)
|
|
187
|
-
target_alt_m = None
|
|
188
|
-
if target_distance is not None:
|
|
189
|
-
target_alt_m = dconvert(target_distance, input_units, "meters")
|
|
190
|
-
|
|
191
|
-
# Integrate in SI
|
|
192
|
-
sim = simulate_radial_flight(
|
|
193
|
-
planet=planet,
|
|
194
|
-
start_altitude=start_distance,
|
|
195
|
-
start_units=input_units,
|
|
196
|
-
v0_mps=v0_mps,
|
|
197
|
-
dt_s=dt_s,
|
|
198
|
-
max_steps=max_steps,
|
|
199
|
-
target_altitude_m=target_alt_m
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
if not sim.get("ok", False):
|
|
203
|
-
return sim
|
|
204
|
-
|
|
205
|
-
# Distances for output
|
|
206
|
-
alt_out = dconvert(sim["altitude_m"], "meters", output_units)
|
|
207
|
-
r_out = dconvert(sim["rFromCenter_m"], "meters", output_units)
|
|
208
|
-
trav_out = dconvert(sim["traveled_m"], "meters", output_units)
|
|
209
|
-
|
|
210
|
-
# Velocity output: (output_units)/(output_time)
|
|
211
|
-
sec_per_out = seconds_per(output_time) # sec / out_timeunit
|
|
212
|
-
v_units_per_sec_out = dconvert(sim["vEnd_mps"], "meters", output_units)
|
|
213
|
-
v_out = mul(v_units_per_sec_out, sec_per_out)
|
|
214
|
-
|
|
215
|
-
# Escape velocity at end
|
|
216
|
-
vesc_units_per_sec_out = dconvert(sim["vEsc_end_mps"], "meters", output_units)
|
|
217
|
-
vesc_end_out = mul(vesc_units_per_sec_out, sec_per_out)
|
|
218
|
-
|
|
219
|
-
# Escape velocity at destination (if provided)
|
|
220
|
-
body = get_body(planet)
|
|
221
|
-
mu = body["mu"]; R = body["radius"]
|
|
222
|
-
destination_radius_m = None
|
|
223
|
-
vesc_dest_out = None
|
|
224
|
-
if target_alt_m is not None:
|
|
225
|
-
destination_radius_m = add(R, target_alt_m)
|
|
226
|
-
vesc_dest_mps = math.sqrt(mul(2.0, div(mu, destination_radius_m)))
|
|
227
|
-
vesc_dest_units_per_sec = dconvert(vesc_dest_mps, "meters", output_units)
|
|
228
|
-
vesc_dest_out = mul(vesc_dest_units_per_sec, sec_per_out)
|
|
229
|
-
|
|
230
|
-
# Time output in requested unit
|
|
231
|
-
t_out = div(sim["time_s"], sec_per_out)
|
|
232
|
-
t_label = output_time if output_time in ("s", "sec", "seconds", "m", "min", "minutes", "h", "hr", "hours") else "s"
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
"ok": True,
|
|
236
|
-
"planet": planet,
|
|
237
|
-
"inputs": {
|
|
238
|
-
"start_distance": start_distance,
|
|
239
|
-
"starting_velocity": starting_velocity,
|
|
240
|
-
"input_units": input_units,
|
|
241
|
-
"input_time": input_time,
|
|
242
|
-
"output_units": output_units,
|
|
243
|
-
"output_time": output_time,
|
|
244
|
-
"target_distance": target_distance,
|
|
245
|
-
},
|
|
246
|
-
"altitude": alt_out, # in output_units
|
|
247
|
-
"radius_from_center": r_out, # in output_units
|
|
248
|
-
"distance_traveled": trav_out, # in output_units
|
|
249
|
-
"velocity": v_out, # in output_units / output_time
|
|
250
|
-
"velocity_escape_end": vesc_end_out, # same units/time as velocity
|
|
251
|
-
"velocity_escape_destination": vesc_dest_out,
|
|
252
|
-
"destination_radius": (
|
|
253
|
-
dconvert(destination_radius_m, "meters", output_units) if destination_radius_m is not None else None
|
|
254
|
-
),
|
|
255
|
-
"time": t_out, # in output_time units
|
|
256
|
-
"time_unit": t_label,
|
|
257
|
-
"g_end_mps2": sim["gAtEnd_mps2"], # keep SI precise for g
|
|
258
|
-
"g_ratio_surface": sim["gRatioSurface"],
|
|
259
|
-
"steps": sim["steps"],
|
|
260
|
-
"hit_surface": sim["hitSurface"],
|
|
261
|
-
"hit_target": sim["hitTarget"],
|
|
262
|
-
"turned_back_below_start": sim["turnedBackBelowStart"],
|
|
263
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
# src/utils/escape_velocity.py
|
|
2
|
-
from ..imports import math, mul, div, add
|
|
3
|
-
from ..constants.planet_constants import get_body
|
|
4
|
-
from ..constants.distance_constants import convert as dconvert
|
|
5
|
-
from ..constants.time_constants import get_time_unit_conversions, normalize_time_unit
|
|
6
|
-
|
|
7
|
-
def _seconds_per(unit: str) -> float:
|
|
8
|
-
"""
|
|
9
|
-
Map a time unit (alias-friendly) to seconds per that unit, using your time schema.
|
|
10
|
-
"""
|
|
11
|
-
return get_time_unit_conversions(normalize_time_unit(unit))["conv"]["seconds"]
|
|
12
|
-
|
|
13
|
-
def escape_velocity_at(
|
|
14
|
-
planet: str = "earth",
|
|
15
|
-
distance: float = 0.0,
|
|
16
|
-
*,
|
|
17
|
-
input_units: str = "meters", # how to interpret `distance`
|
|
18
|
-
output_units: str = "meters", # distance unit for the *speed*
|
|
19
|
-
output_time: str = "s", # time unit for the *speed*
|
|
20
|
-
as_radius: bool = False # False => `distance` is altitude above surface; True => radius from center
|
|
21
|
-
) -> dict:
|
|
22
|
-
"""
|
|
23
|
-
Compute v_escape at a given location around `planet`.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
planet: body name (must exist in PLANETS)
|
|
27
|
-
distance: if as_radius=False => altitude above surface; if as_radius=True => radius from center
|
|
28
|
-
input_units: units of `distance`
|
|
29
|
-
output_units: distance unit of the returned speed
|
|
30
|
-
output_time: time unit of the returned speed ('s'|'min'|'h' etc.)
|
|
31
|
-
as_radius: interpret `distance` as radius-from-center when True
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
{
|
|
35
|
-
"ok": True,
|
|
36
|
-
"planet": str,
|
|
37
|
-
"radius_from_center": <float in output_units>,
|
|
38
|
-
"v_escape": <float in output_units/output_time>,
|
|
39
|
-
"v_escape_mps": <float in m/s>,
|
|
40
|
-
"units": {"distance": output_units, "time": output_time}
|
|
41
|
-
}
|
|
42
|
-
"""
|
|
43
|
-
if not (isinstance(distance, (int, float)) and math.isfinite(distance) and distance >= 0):
|
|
44
|
-
return {"ok": False, "error": "distance must be a non-negative number"}
|
|
45
|
-
|
|
46
|
-
body = get_body(planet)
|
|
47
|
-
mu = body["mu"] # m^3/s^2
|
|
48
|
-
R = body["radius"] # m
|
|
49
|
-
|
|
50
|
-
# Determine radius from center in meters
|
|
51
|
-
if as_radius:
|
|
52
|
-
r_m = dconvert(distance, input_units, "meters")
|
|
53
|
-
else:
|
|
54
|
-
alt_m = dconvert(distance, input_units, "meters")
|
|
55
|
-
r_m = add(R, alt_m)
|
|
56
|
-
|
|
57
|
-
if r_m <= 0:
|
|
58
|
-
return {"ok": False, "error": "computed radius is non-positive"}
|
|
59
|
-
|
|
60
|
-
# v_esc (m/s)
|
|
61
|
-
vesc_mps = math.sqrt(mul(2.0, div(mu, r_m)))
|
|
62
|
-
|
|
63
|
-
# Convert speed to <output_units>/<output_time>
|
|
64
|
-
vesc_units_per_sec = dconvert(vesc_mps, "meters", output_units)
|
|
65
|
-
sec_per = _seconds_per(output_time) # seconds per 1 output_time
|
|
66
|
-
vesc_out = mul(vesc_units_per_sec, sec_per) # <output_units>/<output_time>
|
|
67
|
-
|
|
68
|
-
# Also return the radius in output_units for convenience
|
|
69
|
-
r_out = dconvert(r_m, "meters", output_units)
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
"ok": True,
|
|
73
|
-
"planet": planet,
|
|
74
|
-
"radius_from_center": r_out,
|
|
75
|
-
"v_escape": vesc_out,
|
|
76
|
-
"v_escape_mps": vesc_mps,
|
|
77
|
-
"units": {"distance": output_units, "time": output_time}
|
|
78
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/flask_scripts/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/flask_utils.py
RENAMED
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/__init__.py
RENAMED
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/imports.py
RENAMED
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math/solar_math/src/utils/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_math-0.0.0.24 → abstract_math-0.0.0.25}/src/abstract_math.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|