ENH: Events Class and Flight Rework#968
Draft
MateusStano wants to merge 25 commits into
Draft
Conversation
…ved variables retrieval
…logging Expose recorded sensor measurements as the canonical, per-flight record on `Flight.sensor_data`, and route every flight-scoped consumer through it so results stay correct when a rocket/sensor is reused across simulations. - Sensors: add `flight.sensor_data` as the source of truth; `flight.prints. sensors()` and `flight.plots.sensor_data()` now read from it. Give the per-sensor plots/prints an optional `data=` argument so standalone use still works (`_SensorPlots`, `_SensorPrints`). - Flight plots: improve event markers and the trajectory/ground-track plots (square ground track with equal axis ticks, trajectory omitted from the legend) and related layout cleanups in `flight_plots.py`. - Logging: add a centralized `rocketpy._logging` module exposing `logger`, `set_log_level` and `enable_logging`, following the NullHandler library convention; wire it into the event/simulation code. - Simulation: supporting changes in flight, flight derivatives, flight phases, events (commands, exact-time solvers) and the data exporter. - Stochastic: rebuild the air-brakes `_Controller` with its current signature (controlled_objects / context), fixing a stale constructor call. - Docs: update getting-started and sensors notebooks to the `flight.exports.*` API and document sensor usage.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Event abstraction and refactors the Flight simulation loop to be event-driven, unifying handling of core milestones (out-of-rail/apogee/impact), parachutes, controllers, sensors, and user-defined hooks. It also expands sensor support (plots/prints/export), updates documentation to the new **kwargs trigger/controller patterns, and adds logging configuration utilities.
Changes:
- Added
rocketpy.simulation.events(Event/Commands/exact-time solvers/builders) and new helper modules to evaluate/apply events uniformly during simulation. - Refactored parachute/controller/sensor integration to be event-based, added per-flight sensor data presentation, and updated exporters/docs accordingly.
- Added centralized logging configuration and updated tests/docs to match renamed APIs and new behaviors.
Reviewed changes
Copilot reviewed 82 out of 87 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_plots.py | Marks animation-based unit tests as slow. |
| tests/unit/test_logging.py | Adds unit coverage for RocketPy logging setup and phase-collision warnings. |
| tests/unit/test_flight_data_exporter.py | Updates tests to use new exporter method names (data, pressures, sensor_data, kml). |
| tests/unit/simulation/test_flight.py | Adds regression test for monotonic solution time; updates controller observed-variable expectations. |
| tests/unit/simulation/test_flight_time_nodes.py | Updates tests to target _TimeNodes/_TimeNode internal classes and new event storage shape. |
| tests/unit/simulation/test_event.py | Adds comprehensive unit tests for Event construction, validation, calling, and exact-time behavior. |
| tests/unit/rocket/test_parachute.py | Updates parachute serialization expectations after noise deprecation/removal from dict. |
| tests/unit/rocket/aero_surface/test_linear_generic_surfaces.py | Adapts aero-surface tests to new reynolds computation inputs. |
| tests/unit/rocket/aero_surface/test_generic_surfaces.py | Adapts generic surface tests to new reynolds computation inputs. |
| tests/integration/simulation/test_flight.py | Updates controller logging expectations; adds tests for deprecated positional/kwargs controller APIs. |
| tests/integration/simulation/test_flight_3dof.py | Updates expected simulation_mode string format. |
| tests/integration/simulation/test_event.py | Adds integration tests for event loop behaviors, exact-time solvers, and Commands. |
| tests/fixtures/parachutes/parachute_fixtures.py | Updates parachute trigger fixtures to **kwargs signatures and removes noise usage. |
| tests/acceptance/test_ndrt_2020_rocket.py | Updates acceptance parachute triggers to **kwargs and removes noise usage. |
| tests/acceptance/test_bella_lui_rocket.py | Updates acceptance parachute trigger to **kwargs and removes noise usage. |
| rocketpy/utilities.py | Adds calculate_stall_wind_velocity helper and annotates Flight import cycle. |
| rocketpy/tools.py | Adds inverted_haversine_array for vectorized inverse haversine. |
| rocketpy/stochastic/stochastic_rocket.py | Updates stochastic rocket controller instantiation to new controller fields/shape. |
| rocketpy/simulation/helpers/event_commands.py | Adds command application layer to mutate flight state from event Commands. |
| rocketpy/simulation/helpers/event_calling.py | Adds event-kwargs construction and event-calling orchestration utilities. |
| rocketpy/simulation/helpers/init.py | Exports derivative helpers from the simulation helpers package. |
| rocketpy/simulation/flight_data_exporter.py | Renames exporter methods and provides deprecated export_* aliases. |
| rocketpy/simulation/events/exact_time_solvers.py | Adds exact-time root solvers and root filtering policy helpers. |
| rocketpy/simulation/events/event_builders.py | Adds core event builders (out-of-rail/apogee/impact) and exact-time helpers. |
| rocketpy/simulation/events/commands.py | Adds Commands container used by event callbacks to request simulation actions. |
| rocketpy/simulation/events/init.py | Exposes event module public API. |
| rocketpy/simulation/init.py | Exports Event from simulation package. |
| rocketpy/sensors/sensor.py | Makes sensors event-driven via to_event, adds info/all_info, validates sampling_rate. |
| rocketpy/sensors/gyroscope.py | Adds channels metadata and sensor plots integration. |
| rocketpy/sensors/gnss_receiver.py | Adds channels metadata and sensor plots integration. |
| rocketpy/sensors/barometer.py | Adds channels metadata and sensor plots integration. |
| rocketpy/sensors/accelerometer.py | Adds channels metadata and sensor plots integration. |
| rocketpy/rocket/rocket.py | Adds sensors-by-name, sensor events, and updates airbrakes/controller API + deprecations. |
| rocketpy/rocket/point_mass_rocket.py | Adds _is_point_mass flag for simulation branching/import avoidance. |
| rocketpy/rocket/parachute.py | Wraps parachutes as Events, migrates triggers to **kwargs, deprecates noise, adds trigger_needs. |
| rocketpy/rocket/aero_surface/generic_surface.py | Moves Reynolds computation inside generic surface using density/viscosity inputs. |
| rocketpy/rocket/aero_surface/air_brakes.py | Tweaks airbrakes drag coefficient Function configuration. |
| rocketpy/prints/sensors_prints.py | Adds per-channel measured data summaries. |
| rocketpy/prints/flight_prints.py | Extends flight prints to include sensors, sensor/controller/custom event reporting, and extra maxima. |
| rocketpy/prints/controller_prints.py | Fixes controller source display and handles continuous sampling-rate output. |
| rocketpy/plots/sensors_plots.py | Adds generic sensor plotting utilities for time series and multi-instance sensors. |
| rocketpy/plots/compare/compare_flights.py | Refactors to use show_or_save_plot and expands aerodynamic force comparisons. |
| rocketpy/plots/aero_surface_plots.py | Minor cleanup of header formatting. |
| rocketpy/motors/point_mass_motor.py | Adds _is_point_mass flag for simulation branching/import avoidance. |
| rocketpy/motors/motor.py | Initializes _is_point_mass flag for motors. |
| rocketpy/environment/environment.py | Adds height_above_ground_level Function and keeps it in sync with elevation/pressure profiles. |
| rocketpy/_logging.py | Adds centralized logger, NullHandler default, and enable/level helpers. |
| rocketpy/_encoders.py | Restores additional Flight integration settings and derived lists when decoding minimal flight objects. |
| rocketpy/init.py | Exposes Event and logging helpers at top-level import. |
| docs/user/three_dof_simulation.rst | Updates export examples to use flight.exports.data. |
| docs/user/sensors_usage.rst | Adds new sensors user guide with examples, plots, and export usage. |
| docs/user/rocket/rocket_usage.rst | Updates parachute trigger docs to **kwargs model and deprecations. |
| docs/user/index.rst | Adds Event Usage and Sensors pages to user guide navigation. |
| docs/user/first_simulation.rst | Updates parachute noise usage, adds logging/verbose guidance, updates exporter usage. |
| docs/user/deployable.rst | Removes parachute noise usage from examples. |
| docs/user/compare_flights.rst | Removes parachute noise usage from examples. |
| docs/user/airbrakes.rst | Updates controller examples to **kwargs, removes time_overshoot requirement note, updates logging access. |
| docs/technical/simulation_loop.rst | Adds new technical overview of phase/time-node/event-driven simulation structure. |
| docs/technical/index.rst | Adds Simulation Loop page to technical docs toctree. |
| docs/reference/classes/sensors/gyroscope.rst | Fixes autoclass target to top-level export. |
| docs/reference/classes/sensors/gnss_receiver.rst | Fixes autoclass target to top-level export. |
| docs/reference/classes/sensors/barometer.rst | Fixes autoclass target to top-level export. |
| docs/reference/classes/sensors/accelerometer.rst | Fixes autoclass target to top-level export. |
| docs/notebooks/monte_carlo_analysis/parachute_drop_from_helicopter.ipynb | Updates parachute setup example to new trigger style/noise removal. |
| docs/notebooks/monte_carlo_analysis/monte_carlo_sensitivity_simulation.py | Removes parachute noise usage. |
| docs/notebooks/monte_carlo_analysis/monte_carlo_class_usage.ipynb | Removes parachute noise usage. |
| docs/notebooks/monte_carlo_analysis/monte_carlo_analysis.ipynb | Removes legacy drogue trigger cell and noise usage; clears execution counts. |
| docs/notebooks/getting_started_colab.ipynb | Updates to new exporter usage and removes parachute noise usage. |
| docs/examples/valetudo_flight_sim.ipynb | Removes parachute noise usage. |
| docs/examples/ndrt_2020_flight_sim.ipynb | Removes parachute noise usage. |
| docs/examples/lince_flight_sim.ipynb | Removes parachute noise usage. |
| docs/examples/juno3_flight_sim.ipynb | Removes parachute noise usage. |
| docs/examples/hedy_flight_sim.ipynb | Removes parachute noise usage and related config keys. |
| docs/examples/genesis_flight_sim.ipynb | Removes parachute noise usage. |
| docs/examples/bella_lui_flight_sim.ipynb | Removes parachute noise usage. |
| docs/development/testing.rst | Removes an obsolete TODO comment from testing docs. |
| .pylintrc | Increases max-statements threshold and adjusts a lint rule configuration. |
Comment on lines
+612
to
+630
| theta = np.radians(flight.inclination) | ||
| stall_angle = np.radians(stall_angle) | ||
|
|
||
| c = (np.cos(stall_angle) ** 2 - np.cos(theta) ** 2) / np.sin(stall_angle) ** 2 | ||
| w_v = ( | ||
| 2 * v_f * np.cos(theta) / c | ||
| + ( | ||
| 4 * v_f * v_f * np.cos(theta) * np.cos(theta) / (c**2) | ||
| + 4 * 1 * v_f * v_f / c | ||
| ) | ||
| ** 0.5 | ||
| ) / 2 | ||
|
|
||
| stall_angle = np.degrees(stall_angle) | ||
| print( | ||
| "Maximum wind velocity at Rail Departure time before angle" | ||
| + f" of attack exceeds {stall_angle:.3f}°: {w_v:.3f} m/s" | ||
| ) | ||
| return w_v |
Comment on lines
+356
to
+361
| - ``state_dot`` (list of float): time derivative of the state vector, | ||
| ``[vx, vy, vz, ax, ay, az, e0_dot, e1_dot, e2_dot, e3_dot, w1_dot, w2_dot, w3_dot]``. | ||
| In particular, ``(ax, ay, az)`` at indices 3, 4 and 5 are the acceleration | ||
| components, so ``state_dot[5]`` is the vertical acceleration. | ||
| - ``pressure`` (float): current atmospheric pressure in Pa at the rocket's | ||
| altitude. |
Comment on lines
+375
to
+377
| - ``sensors`` (dict): dictionary mapping sensor names (or class names) to sensor | ||
| instances, each exposing its most recent ``measurement``. If several sensors | ||
| share a name, the value is a list. |
Comment on lines
+1826
to
+1831
| .. deprecated:: 1.13 | ||
| Passing `initial_observed_variables` directly to | ||
| ``add_air_brakes`` is deprecated. Provide initial observed | ||
| variables via the ``context`` parameter as | ||
| ``context={'observed_variables': [...]}`` instead. Support | ||
| for the positional argument will be removed in v1.13. |
Comment on lines
+263
to
+272
| if noise[0] != 0 or noise[1] != 0 or noise[2] != 0: | ||
| warnings.warn( | ||
| "The `noise` parameter on Parachute is deprecated and has no " | ||
| "effect; it will be removed in v1.13. Use a Sensor (e.g. a " | ||
| "Barometer) with built-in noise instead, and read the noisy " | ||
| "measurement via `kwargs['sensors_by_name']` in your trigger " | ||
| "function.", | ||
| DeprecationWarning, | ||
| stacklevel=3, | ||
| ) |
Comment on lines
+271
to
+273
| z : float | ||
| Altitude of the surface, used to evaluate ``density`` and | ||
| ``dynamic_viscosity``. |
Member
There was a problem hiding this comment.
let it clear if its above sea level ou ground level please
z : float
Altitude of the surface, used to evaluate ``density`` and
``dynamic_viscosity``.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The addition of custom events was long overdue. In this PR the Event class was added. It was basically impossible to do this without changing a lot of the flight class, so I took the opportunity to rework it and solve all TODOs there.
Several upcoming features will build on top of this (parafoil, multistage, more controllers...), so I want this branch to act as a hub for a few related changes:
class Eventserializableflight.solutionan instance of a newSolutionclass. It should behave like the current array, but also allow a variable state length. This is important for adding new parachute models such as parafoil, and for letting us define more complex derivative functions.GenericSurfacethe mother class of all other aero surfaces.Here is a summary of all the changes:
flight.pySome flight class methods were reworked, some were moved:
flight_derivatives.py: the motion functions (u_dot,u_dot_generalized,u_dot_generalized_3dof, rail and parachute), moved out offlight.py.flight_phase.py: now has the_FlightPhasesand_TimeNodesclasses.event_calling.py: utilities for callling the events in the flight class correctlyevent_commands.py: applies the commands an event returns back to the flight.New event code (
rocketpy/simulation/events/)event.py(Event): An event has a trigger and a callback. The trigger is checked each step; when it is true, the callback runs. Callbacks can read the state, save data, log results, and send commands that change the simulation. It comes with ready-made presets likeapogeeandburnout. It also only computes expensive values when an event actually needs them.commands.py(Commands): what a callback can ask for. An event can start anew phase, swap the motion function, turn other events on or off, add or
remove controllers, undo a step (rollback), or stop the flight.
event_builders.py: ready-made events that recreate the normal flight steps(like leaving the rail).
exact_time_solvers.py: finds the exact time an event happens inside a step(using a few math methods).
Parachutes, controllers and sensors are no longer special cases in the flight loop. Each one now has a
to_event()method that wraps it into anEvent. The built-in flight milestones (apogee, out of rail, impact) are now events too.Parachute triggers and Controllers controller_function now take
**kwargsonly and read what they need by name (pressure,height_agl,state,sensors, etc.); the old positional parachute and controller signatures still work but raise aDeprecationWarning.Flight.__init_events()just collects all events (core events, then sensors, parachutes, controllers, and user custom events) and runs them uniformly, and commands an event returns (like swapping the derivative or starting a phase) are applied back to the flight byevent_commands.py.Parachute noise was also removed. The
noiseparameter onParachuteis now deprecated and has no effect (removal in v1.13). To model a noisy trigger, aBarometershould be used and accesses the noisy measurement in the trigger viakwargs['sensors_by_name']. This fits the new model, where sensors are events and the trigger reads their measurements.Plots and prints
flight_plots.pyandflight_prints.pynow show sensor data too.compare_flights.pyupdated.Docs
docs/user/event_usage.rstanddocs/user/sensors_usage.rst.docs/technical/simulation_loop.rst.Notes for reviewers
This will be a difficult one to review, specially because the diff tracking in flight.py is not that helpful given I changed the order of a few methods. So I suggest that the best way to understand how events work is to read the user guide:
docs/user/event_usage.rst. It walks through the API with runnable examples.Breaking change