Repository navigation
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
Changes from 15 commits
64b2ea9
c4ef363
45032d8
bf0c365
6836650
edf06e5
e56e6d4
8d1027e
dc8acf2
ff59ada
5b545b0
73e0789
f0a5903
99c6214
7234995
4109660
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -224,6 +224,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/bash
set -euo pipefail
echo "Files matching flight.py:"
fd -a 'flight.py$' . || true
echo
echo "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'
fi
echo
echo "Relevant sections:"
for start in 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
done
echo
echo "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/bash
set -euo pipefail
echo "src/controllers/flight.py relevant section:"
sed -n '180,240p' src/controllers/flight.py | cat -n
echo
echo "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
echo
echo "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'
echo
echo "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 +256,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/bash
set -euo pipefail
echo "== relevant files =="
git ls-files | rg '(^src/services/flight.py$|rocketpy|tank|geometry)' | sed -n '1,120p'
echo
echo "== 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' || true
echo
echo "== lines 220-310 =="
sed -n '220,310p' src/services/flight.py | nl -ba -v220
echo
echo "== 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/bash
set -euo pipefail
echo "== src/services/flight.py lines 247-330 =="
sed -n '247,330p' src/services/flight.py
echo
echo "== src/models/sub/tanks.py =="
cat -n src/models/sub/tanks.py
echo
echo "== imports and serialization helpers =="
sed -n '1,120p' src/services/flight.py
echo
echo "== 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/bash
set -euo pipefail
python3 - <<'PY'
import ast
from pathlib import Path
src = 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/bash
set -euo pipefail
echo "== inspect _build_rocketpy_tank_geometry =="
sed -n '40,62p' src/services/motor.py
echo
echo "== inspect _generate_positioned_tanks if present in installed rocketpy =="
python3 - <<'PY'
import inspect
try:
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, | ||
|
|
||
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.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 3177
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 1224
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 14542
🏁 Script executed:
Repository: RocketPy-Team/Infinity-API
Length of output: 8123
Enforce
GENERICburn_timein the model validator.POST /motorsbuildsMotorModel, thenMotorRepository.create_motorpersistsmotor.model_dump(exclude_none=True). TheGENERICburn_timecheck lives only inMotorService.from_motor_model, so a malformedGENERICmotor can be stored and fail later. Add the same POST-level check used for solid/grain parameters and other motor-kind requirements inMotorModel.validate_motor_kind.🤖 Prompt for AI Agents