Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3
feat(motor,flight): tank geometry + fluid density inputs, KML export#72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
64b2ea9c4ef36345032d8bf0c3656836650edf06e5e56e6d48d1027edc8acf2ff59ada5b545b073e0789f0a590399c621472349954109660File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -160,4 +160,10 @@ cython_debug/ | ||
| #.idea/ | ||
| # VSCode config | ||
| .vscode/ | ||
| .vscode/ | ||
| # context specific ignores | ||
| .context | ||
| # lint | ||
| .pylint.d/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -20,7 +20,11 @@ class MotorModel(ApiBaseModel): | ||
| # Required parameters | ||
| thrust_source: List[List[float]] | ||
| burn_time: float | ||
| # burn_time is optional for Liquid/Hybrid/Solid motors — rocketpy | ||
| # auto-detects the burn window from the thrust_source array span. | ||
| # GenericMotor still requires it; the motor service re-raises an | ||
| # explicit error when the GENERIC path receives None. | ||
| burn_time: Optional[float] = None | ||
Comment on lines
+23
to
+27
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash# Description: Check whether MotorController.post_motor builds the rocketpy motor synchronously.
fd -e py motor.py --full-path src/controllers | xargs -I{} sh -c 'echo "--- {} ---"; cat -n {}'Repository: RocketPy-Team/Infinity-API Length of output: 3177 🏁 Script executed: #!/bin/bashset -euo pipefail
echo"Tracked controller files:"
git ls-files 'src/controllers/*.py'echo"--- MotorController methods ---"
rg -n "def (create|create_?motor|post|get|update|delete|add|upsert|fetch)|motor_id|motor\.motor|MotorModel|get_motor_by_id" src/controllers/motor.py
echo"--- motor.py line count ---"
wc -l src/controllers/motor.pyRepository: RocketPy-Team/Infinity-API Length of output: 1224 🏁 Script executed: #!/bin/bashset -euo pipefail
echo"--- src/controllers/interface.py relevant sections ---"
wc -l src/controllers/interface.py
sed -n '1,220p' src/controllers/interface.py | cat -n
echo"--- src/api.py imports and registered motor/controller routes ---"
wc -l src/api.py
rg -n "MotorController|motor|controllers|router|BaseController|create" src/api.py -C 3
echo"--- MotorModel and service validation snippets ---"
wc -l src/models/motor.py src/services/motor.py
sed -n '1,130p' src/models/motor.py | cat -n
sed -n '220,260p' src/services/motor.py | cat -nRepository: RocketPy-Team/Infinity-API Length of output: 14542 🏁 Script executed: #!/bin/bashset -euo pipefail
echo"--- create_motor methods in motor controllers/repositories ---"
rg -n "def create_motor|create_motor\\(" src/controllers src/repositories src/routes -C 6
echo"--- motor router outline and relevant snippets ---"
wc -l src/routes/motor.py
sed -n '1,220p' src/routes/motor.py | cat -n
echo"--- motor repository filenames and create_motor snippets ---"
git ls-files 'src/repositories/*motor*''src/repositories/motor.py'
fd -e py 'motor|Motor' src/repositories -x sh -c 'echo "--- $1 ---"; rg -n "create_motor|create_model|NAME" "$1" -C 5' sh {}Repository: RocketPy-Team/Infinity-API Length of output: 8123 Enforce
🤖 Prompt for AI Agents | ||
| nozzle_radius: float | ||
| dry_mass: float | ||
| dry_inertia: Tuple[float, float, float] = (0, 0, 0) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,12 @@ | ||
| import json | ||
| import os | ||
| import tempfile | ||
| from typing import Self, Tuple | ||
| import numpy as np | ||
| from rocketpy.simulation.flight import Flight as RocketPyFlight | ||
| from rocketpy.simulation.flight_data_exporter import FlightDataExporter | ||
| from rocketpy._encoders import RocketPyEncoder, RocketPyDecoder | ||
| from rocketpy.mathutils.function import Function | ||
| from rocketpy.motors.solid_motor import SolidMotor | ||
| @@ -224,6 +227,22 @@ def _to_float(value) -> float: | ||
| case _: | ||
| return float(value) | ||
| @staticmethod | ||
| def _extract_fluid_density(fluid): | ||
| """Project a rocketpy Fluid's density back onto the API schema. | ||
| The API accepts either a scalar or a list of (T_K, density) | ||
| samples. Rocketpy may store density as either a raw scalar or a | ||
| ``Function`` wrapping a 2D ``(T, P) -> density`` callable. A | ||
| full sample round-trip is not supported in this iteration; | ||
| Function-valued densities are collapsed to a scalar evaluated | ||
| at rocketpy's default reference (273.15 K, 101325 Pa). | ||
| """ | ||
| density = fluid.density | ||
| if isinstance(density, Function): | ||
| return float(density(273.15, 101325)) | ||
| return density | ||
Comment on lines
+230
to
+244
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bashset -euo pipefail
echo"Files matching flight.py:"
fd -a 'flight.py$'.||trueechoecho"Outline src/services/flight.py:"if [ -f src/services/flight.py ];then
wc -l src/services/flight.py
ast-grep outline src/services/flight.py --view expanded | sed -n '1,220p'fiechoecho"Relevant sections:"forstartin 1 180 210 280 380 460 540;do
end=$((start+120))echo"--- src/services/flight.py $start-$end"
sed -n "${start},${end}p" src/services/flight.py
doneechoecho"Search DensityInput and extract_models:"
rg -n "DensityInput|extract_models|import_flight_from_rpy|_extract_fluid_density|density_input|fluid_dens|fluid" src tests | sed -n '1,240p'Repository: RocketPy-Team/Infinity-API Length of output: 33062 🏁 Script executed: #!/bin/bashset -euo pipefail
echo"src/controllers/flight.py relevant section:"
sed -n '180,240p' src/controllers/flight.py | cat -n
echoecho"src/services/motor.py fluid construction:"
sed -n '55,100p' src/services/motor.py | cat -n
sed -n '250,275p' src/services/motor.py | cat -n
echoecho"MotorService round-trip usages:"
rg -n "from_models|from_motor_model|extract_models|get_models|_build_rocketpy_fluid|Fluid\\(" src/services/motor.py src/services/flight.py src/services/*.py | sed -n '1,220p'echoecho"Search for create flight from model round-trip:"
rg -n "FlightService\\.(from_flight_model|extract_models)|import_flight_from_rpy|from_motor_model" src tests | sed -n '1,220p'Repository: RocketPy-Team/Infinity-API Length of output: 10363 Preserve temperature-sampled fluid density during import.
🤖 Prompt for AI Agents | ||
| @staticmethod | ||
| def _extract_tanks(motor) -> list[MotorTank]: | ||
| tanks: list[MotorTank] = [] | ||
| @@ -240,20 +259,29 @@ def _extract_tanks(motor) -> list[MotorTank]: | ||
| case _: | ||
| tank_kind = TankKinds.MASS_FLOW | ||
| geometry = [ | ||
| # Geometry round-trip is lossy: even if the client originally | ||
| # sent a cylindrical/spherical geometry, we discretise it back | ||
| # to the generic piecewise form on read. Every rocketpy tank | ||
| # geometry exposes its internal piecewise dict via | ||
| # `tank.geometry.geometry`, so this path covers all three | ||
| # geometry subclasses uniformly. | ||
| geometry_segments = [ | ||
| (bounds, float(func(0))) | ||
| for bounds, func in tank.geometry.geometry.items() | ||
| ] | ||
Comment on lines
+262
to
271
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bashset -euo pipefail
echo"== relevant files =="
git ls-files | rg '(^src/services/flight.py$|rocketpy|tank|geometry)'| sed -n '1,120p'echoecho"== outline src/services/flight.py around import/export =="
ast-grep outline src/services/flight.py --view expanded 2>/dev/null | sed -n '1,220p'| rg -n 'def|class|flight|tank|import|serde|geometry'||trueechoecho"== lines 220-310 =="
sed -n '220,310p' src/services/flight.py | nl -ba -v220
echoecho"== search geometry classes/config =="
rg -n "class .*Tank|Geometry|geometry\.geometry|TankGeometry|Tank|tank\.geometry|rocketpy" src tests -g '*.py'| sed -n '1,240p'Repository: RocketPy-Team/Infinity-API Length of output: 1357 🌐 Web query:
💡 Result: In RocketPy, the TankGeometry class is used to define the geometry of an axi-symmetric tank by specifying its radius as a function of its height along the axis of symmetry [1][2]. The geometry is defined using a dictionary provided to the geometry_dict parameter [3][4]. This dictionary allows for the construction of complex, piecewise defined shapes [1][5]. Key details regarding the TankGeometry attribute: 1. The geometry attribute is a dictionary where each key is a disjoint tuple (lower_bound, upper_bound) representing a domain along the tank's symmetry axis in meters [1][3]. 2. The corresponding values are functions (typically Python lambdas or RocketPy.Function objects) that map the tank's height to its radius at that specific section [1][2]. 3. Because the dictionary can contain multiple disjoint domains, the tank's overall radius profile is effectively a piecewise-defined function [1][5][6]. While users can manually define geometries using this dictionary approach for arbitrary shapes, RocketPy also provides convenience classes such as CylindricalTank and SphericalTank for standard configurations [3][4]. For example, a spherical tank can be defined using the geometry dictionary by specifying a radius function such as lambda h: (radius2 - h2)(1/2) over the domain (-radius, radius) [1][2]. The internal logic of TankGeometry then computes the overall radius, area, and volume functions based on these inputs [1][5]. Citations:
🏁 Script executed: #!/bin/bashset -euo pipefail
echo"== src/services/flight.py lines 247-330 =="
sed -n '247,330p' src/services/flight.py
echoecho"== src/models/sub/tanks.py =="
cat -n src/models/sub/tanks.py
echoecho"== imports and serialization helpers =="
sed -n '1,120p' src/services/flight.py
echoecho"== tank field serialization references =="
rg -n "MotorTank|tank|geometry|_extract_tanks|rpy|from_rpy" src -g '*.py'| sed -n '1,260p'Repository: RocketPy-Team/Infinity-API Length of output: 28255 🏁 Script executed: #!/bin/bashset -euo pipefail
python3 - <<'PY'import astfrom pathlib import Pathsrc = Path('src/services/flight.py').read_text()tree = ast.parse(src, filename='src/services/flight.py')for node in tree.body: if node.name == 'FlightService': for cls in node.body: if isinstance(cls, ast.FunctionDef) and cls.name == '_extract_tanks': src_snippet = src.splitlines()[cls.lineno-1:cls.end_lineno] print(f'function: {cls.name} lines {cls.lineno}-{cls.end_lineno}') lines = [ ('geometry_segments =', any('geometry_segments = [' in line for line in src_snippet)), ('evaluating func(0) explicitly:', any('func(0)' in line for line in src_snippet)), ('custom geometry_kind:', any('geometry_kind": "custom"' in line for line in src_snippet)), ('tank geometry dict:', any('tank.geometry.geometry.items()' in line for line in src_snippet)), ] for label, ok in lines: print(f'{label}: {ok!s}') print('target block:') for i, line in enumerate(src_snippet, start=cls.lineno): print(f'{i}: {line}')PYRepository: RocketPy-Team/Infinity-API Length of output: 442 🏁 Script executed: #!/bin/bashset -euo pipefail
echo"== inspect _build_rocketpy_tank_geometry =="
sed -n '40,62p' src/services/motor.py
echoecho"== inspect _generate_positioned_tanks if present in installed rocketpy =="
python3 - <<'PY'import inspecttry: import rocketpy from rocketpy import LevelBasedTank, MassBasedTank, UllageBasedTank print('rocketpy imported', getattr(rocketpy, '__version__', '')) for name, cls in [('LevelBasedTank', LevelBasedTank), ('MassBasedTank', MassBasedTank), ('UllageBasedTank', UllageBasedTank)]: print(f'\n{name}:') print(inspect.signature(cls)) print('methods:', sorted([m for m in dir(cls) if not m.startswith('_') and callable(getattr(cls, m))])) if hasattr(cls, 'plots') and hasattr(getattr(cls, 'plots'), '_generate_positioned_tanks'): print(inspect.getsource(cls.plots._generate_positioned_tanks))except Exception as exc: print(type(exc).__name__ + ': ' + str(exc))PYRepository: RocketPy-Team/Infinity-API Length of output: 1101 Preserve position-dependent tank geometry during import.
🤖 Prompt for AI Agents | ||
| data: dict = { | ||
| "geometry": geometry, | ||
| "geometry": { | ||
| "geometry_kind": "custom", | ||
| "geometry": geometry_segments, | ||
| }, | ||
| "gas": TankFluids( | ||
| name=tank.gas.name, | ||
| density=tank.gas.density, | ||
| density=FlightService._extract_fluid_density(tank.gas), | ||
| ), | ||
| "liquid": TankFluids( | ||
| name=tank.liquid.name, | ||
| density=tank.liquid.density, | ||
| density=FlightService._extract_fluid_density(tank.liquid), | ||
| ), | ||
| "flux_time": tank.flux_time, | ||
| "position": position, | ||
| @@ -474,6 +502,25 @@ def get_flight_simulation(self) -> FlightSimulation: | ||
| flight_simulation = FlightSimulation(**encoded_attributes) | ||
| return flight_simulation | ||
| def get_flight_kml(self) -> bytes: | ||
| """ | ||
| Get the flight trajectory as a KML file for Google Earth. | ||
| Returns: | ||
| bytes (UTF-8 encoded KML) | ||
| """ | ||
| with tempfile.NamedTemporaryFile( | ||
| suffix=".kml", delete=False | ||
| ) as tmp: | ||
| tmp_path = tmp.name | ||
| try: | ||
| FlightDataExporter(self.flight).export_kml(file_name=tmp_path) | ||
| with open(tmp_path, "rb") as fh: | ||
| return fh.read() | ||
| finally: | ||
| if os.path.exists(tmp_path): | ||
| os.unlink(tmp_path) | ||
| def get_flight_rpy(self) -> bytes: | ||
| """ | ||
| Get the portable JSON ``.rpy`` representation of the flight. | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 50382
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 46105
Move KML generation off the event-loop thread.
get_flight_kmlstill runsFlightService.from_flight_model(...).get_flight_kml()synchronously after awaiting the database read, and the controller is awaited by the FastAPI route handler. The export creates a temp file, reads it, and deletes it synchronously, so a long KML export blocks the shared event loop.Run the complete synchronous export path in a worker thread.
🤖 Prompt for AI Agents