ENH: Refactor Aero Surface, Make GenericSurface the Mother Class - #1064
MateusStano wants to merge 27 commits into
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Every aerodynamic surface is now rooted in GenericSurface and stores its force coefficients in the body frame (cN/cY/cA) plus the cm/cn/cl moments, exposing all nine coefficients (cL/cD/cQ/cN/cY/cA/cm/cn/cl) with the wind trio lazily derived. A force_convention argument lets users supply wind- or body-frame coefficients. Barrowman surfaces (nose, tail, fin sets) keep the classic geometric normal-force/moment method, report the force at the geometric center of pressure via the classic 180-degree surface rotation, and expose cN_alpha/cY_beta stability slopes (the old clalpha relabelled). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the poorly defined calisto_linear_generic fixture, which kept the Barrowman nose cone and tail and swapped only the fins for a LinearGenericSurface with arbitrary made-up coefficients. The new fixture is a standalone Calisto whose nose cone, tail and fins are all LinearGenericSurfaces built from coefficient curves extracted off the standard Barrowman surfaces (normal-force-curve slope, center of pressure, fin roll damping). Each linear surface applies its force at its own origin and is placed at the source surface's center-of-pressure station, so both the static-margin path and the flight-moment path land at the same point as calisto_robust. The resulting flight matches the standard Calisto (identical apogee, out-of-rail time and ascent angle of attack), so the fixture now exercises the linear generic-surface path against a known-good reference. Also fix test_linear_generic_surface_flight_is_stable to check the angle of attack only during the ascent off the rail: on the rail the freestream speed is ~0 and the angle of attack is reported as a degenerate 90 degrees for any launcher, which previously failed the < 45 assertion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## enh/events #1064 +/- ##
=============================================
Coverage ? 81.88%
=============================================
Files ? 129
Lines ? 16880
Branches ? 0
=============================================
Hits ? 13822
Misses ? 3058
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
I checked two behaviors from the upstream worklist on head Scalar coefficients
Wind-to-body force mapping (#932) At Those match Both pieces appear covered by this draft, but the branch also includes a substantially larger aerodynamic redesign. If a smaller review unit would help, the scalar Environment: Python 3.12.6; NumPy 2.5.2; pytest 9.1.1; macOS 26.5.2 arm64. Current |
|
This is a huge PR, yet not finished tho |
Conflicts were resolved toward the event context design of enh/events: - controller.py, rocket.py: the controller save/load fix from 3260573 is ported to the context convention. The controlled-object hashes are still saved so a loaded rocket reconnects its controllers, controller_needs is dropped since the context works values out when first read, and the legacy air brakes wrapper keeps the 7-argument form but passes the live context["controlled_objects"] instead of the captured air brakes. - event.py, event_builders.py, event_calling.py, event_commands.py, flight_phase.py: docstrings follow the new signatures (no needs or kwargs), keeping the reworded text where the parameter still exists. - tests/unit/simulation/test_flight.py: both import additions kept. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Rocket.stability_margin takes (mach, time) again, at zero angle of attack - aerodynamic center counts each surface's whole moment (pure couples, axial force at a sideways offset, canted individual fins) - Rocket.disturbance_response and Flight.disturbance_response, built on attitude oscillator helpers shared with the flight's dynamic stability - GenericSurface: data against alpha_total is split between the pitch and yaw planes from the variable name alone, also for lift and drag; force_convention is only "body" or "wind" - LinearGenericSurface(axisymmetric=True) fills in the yaw-plane derivatives; add_full_body_aerodynamics no longer takes symmetric - remove angular_position from GenericSurface
- stability guide: simpler center of pressure section, displayed C1 and C2 equations, disturbance response section, parts 6 and 7 removed - generic surface guide: full list of variable names, total angle of attack by variable name, axisymmetric linear surfaces - rocket usage: drag curve at an angle of attack, stability_margin(mach, time)
A GenericSurface takes a rate derivative such as cm_q next to a coefficient, to add damping to tabulated data: it is multiplied by its reduced rate and added to the coefficient. Documented in the generic surface guide.
Brings in the attribute-style event context (`context.state.vz`, `context.state_dot.az`, `context.controlled`) and the move of the event code from `simulation/helpers` to `simulation/events`. Conflict in `rocketpy/control/controller.py`: kept the `enh/events` side, where `__build_controlled` replaces `__verify_controlled_objects_name`. Ported two places that merged cleanly but still used what that commit removed: - `_Controller.rebind_controlled_objects` now rebuilds `context.controlled` from the reconnected objects. - The wrapper for legacy positional air brake controllers reads the air brakes from `context["controlled"][0]` instead of `context["controlled_objects"]`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A surface's `active_during` now accepts only "always", "power_on" and
"power_off". The function form `active_during(t, flight)` is removed:
to switch a surface at any other moment, an event calls one of two new
commands from its callback,
context.event.commands.activate_surface(surface)
context.event.commands.deactivate_surface(surface)
and the solver restarts at the switch. A surface that only appears
later in the flight is built with the new `active=False` argument, so
that it starts each flight switched off.
The flight stores each switch with its time, so `surface.is_active(t,
flight)` is still a plain question about time and the outputs computed
after the flight see the surfaces that were on at each moment. The
surfaces themselves are not modified, so another flight of the same
rocket starts from their own `active` setting.
The stability analysis leaves out a surface built with `active=False`.
… name GenericSurface, LinearGenericSurface and ControllableGenericSurface now take their shared arguments in the same order, with each class's own argument last (`axisymmetric`, `controls`). ControllableGenericSurface had `interpolation`/`extrapolation` and `force_convention`/ `active_during` swapped relative to the other two. Every argument after `name` is keyword-only. The first five arguments are the ones released on master and can still be passed by position.
Add a "Which drag is used" section to the generic surfaces guide: the
rocket's own drag curves always apply, every surface's axial force is
added on top, and `overwrite=True` in `add_full_body_aerodynamics`
removes the existing surfaces and zeroes both drag curves. Warn that
full-vehicle data that already includes drag is counted twice otherwise.
Also fix a typo ("collapses" to "collapse").
- Remove unused imports and the unused `plane` argument of `_draw_center_of_mass_and_pressure`. - Give every `to_dict` override the `include_outputs` argument of its base class. - Explain and disable the warnings that misread a deliberate pattern: `_BaseFin` initializes `GenericSurface` later, `Fin` and `Fins` are still abstract, and `u_dot_parachute` keeps the shared `t` argument. - Disable too-many-lines in `rocket.py` and `flight.py`, too-many-locals in `full_body_coefficients` and too-many-statements in `AeroCoefficient.__init__`. - Allow names like `M1_cm` in `.pylintrc`. - Tests: move imports to the top, use dict literals, drop unused variables and arguments.
dict.update has no inspectable signature, so passing it directly as an Event callback fails; restore the lambda and silence the pylint hint. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # rocketpy/plots/aero_surface_plots.py # rocketpy/rocket/aero_surface/fins/fin.py # rocketpy/rocket/aero_surface/fins/fins.py # rocketpy/simulation/helpers/flight_derivatives.py # tests/unit/simulation/test_dynamics.py # tests/unit/simulation/test_event.py # tests/unit/simulation/test_solution.py
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
All aerodynamic surfaces now come from one mother class,
GenericSurface. Before, the nose cone, fins and tail each had their own way of computing forces. Now they all describe themselves with the same set of coefficients, and the flight treats every surface the same way.I took the opportunity to rework how coefficients are stored, to add full-vehicle aerodynamics, and to redo the stability analysis on top of it.
Here is a summary of all the changes:
Aerodynamic surfaces (
rocketpy/rocket/aero_surface/)GenericSurfaceis now the mother class of every surface:NoseCone, all fins,Tail,RailButtonsandAirBrakes._BarrowmanSurface: new private base for the surfaces that use Barrowman equations (nose, fins, tail).AeroCoefficient: new class that holds one coefficient. It accepts a number, a function, aFunction, a list of points or a CSV file, and only keeps the variables the coefficient really depends on.ControllableGenericSurface: new surface whose coefficients also depend on control variables, such as a canard deflection.AirBrakesis now one of these.AeroSurfaceis deprecated. It still works andisinstance(surface, AeroSurface)is still true.New options on
GenericSurfaceandLinearGenericSurface:cN,cY,cA) or the wind frame (cL,cQ,cD), chosen withforce_convention.from_csv).alpha_total).cm_qnext to a tabulated coefficient, to add damping.interpolationandextrapolationoptions for tabulated coefficients.reynolds_length, to use a different length for the Reynolds number.axisymmetric=TrueonLinearGenericSurface, to give only the pitch-plane derivatives.active_during("always","power_on","power_off") andactive, to make a surface work only in part of the flight.nameis keyword-only.Rocket
add_full_body_aerodynamics: describe the whole rocket with one surface (from CFD, wind tunnel, OpenRocket...).overwrite=Trueremoves the other surfaces and clears the drag curves.to_coefficientsandto_surface: turn an assembled rocket into one set of coefficients, or one surface.power_on_dragandpower_off_dragcan now depend on more than Mach (angle of attack, Reynolds, rotation rates).aerodynamic_center,center_of_pressure,neutral_point,static_margin,stability_marginand their_yawtwins.stability_phase: choose if the stability numbers describe the powered or the coasting rocket.disturbance_response: how the rocket oscillates after a disturbance.is_axisymmetric,is_incidence_linearandlength.Flight
stability_margin_yaw,static_margin_yaw, min, max, out of rail).pitch_natural_frequency,pitch_damping_ratio, their yaw versions,corrective_moment_coefficient,damping_moment_coefficientanddisturbance_response.activate_surfaceanddeactivate_surface, to switch a surface on or off at any moment of the flight.Function
Function.from_regular_grid_csvandinterpolation="regular_grid"are deprecated.Fixes
masterfor a rocket with propellant.Plots and prints
Flight.plots(stability_margin_data,stability_and_control_data,stability_summary) andRocket.plots.stability_margin_yaw.Docs
docs/user/rocket/generic_surface.rstrewritten: frames, coefficients, CSV files, damping, interpolation, activation, whole-vehicle aerodynamics.docs/user/center_of_pressure_and_stability.rst.ControllableGenericSurface,PointMassRocket,PointMassMotor,EmptyMotor,StochasticAirBrakes.Notes for reviewers
The diff is large. The best way in is to read the two guides above, then
aero_coefficient.pyandgeneric_surface.py. The other surfaces are small once those two are clear.Breaking change
AeroSurfaceis deprecated in favor ofGenericSurface.Function.from_regular_grid_csvandinterpolation="regular_grid"are deprecated.