Skip to content

ENH: Events Class and Flight Rework#968

Draft
MateusStano wants to merge 25 commits into
developfrom
enh/events
Draft

ENH: Events Class and Flight Rework#968
MateusStano wants to merge 25 commits into
developfrom
enh/events

Conversation

@MateusStano

@MateusStano MateusStano commented Jun 15, 2026

Copy link
Copy Markdown
Member

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:

  • Make class Event serializable
    • Fix broken tests (broken due to fails on controller serialization)
  • Rework controllers (minor) so they are better designed for use with specific classes, like what is done in FEAT: new actuator class for roll, throttle, and thrust vector control #965.
  • Make flight.solution an instance of a new Solution class. 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.
  • Aerodynamic classes refactor to make GenericSurface the mother class of all other aero surfaces.

Here is a summary of all the changes:

flight.py

Some flight class methods were reworked, some were moved:

  • The flight now moves forward using events, not a fixed list of phases.
  • flight_derivatives.py: the motion functions (u_dot, u_dot_generalized,
    u_dot_generalized_3dof, rail and parachute), moved out of flight.py.
  • flight_phase.py: now has the _FlightPhases and _TimeNodes classes.
  • event_calling.py: utilities for callling the events in the flight class correctly
  • event_commands.py: applies the commands an event returns back to the flight.
  • a propper logging feature was added

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 like apogee and burnout. 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 a
    new 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 an Event. The built-in flight milestones (apogee, out of rail, impact) are now events too.

Parachute triggers and Controllers controller_function now take **kwargs only and read what they need by name (pressure, height_agl, state, sensors, etc.); the old positional parachute and controller signatures still work but raise a DeprecationWarning.

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 by event_commands.py.

Parachute noise was also removed. The noise parameter on Parachute is now deprecated and has no effect (removal in v1.13). To model a noisy trigger, a Barometer should be used and accesses the noisy measurement in the trigger via kwargs['sensors_by_name']. This fits the new model, where sensors are events and the trigger reads their measurements.

Plots and prints

  • flight_plots.py and flight_prints.py now show sensor data too.
  • compare_flights.py updated.
  • New plots to all_info, and now they show case events:
image

Docs

  • New guides: docs/user/event_usage.rst and docs/user/sensors_usage.rst.
  • New technical page: docs/technical/simulation_loop.rst.
  • Update all places that used old definition of trigger functions (with positional arguments) to now be used with **kwargs

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

  • No (I hope)

…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.
@MateusStano MateusStano requested a review from a team as a code owner June 15, 2026 17:39
@MateusStano MateusStano added Enhancement New feature or request, including adjustments in current codes Parachute Related to parachutes methods and usage Refactor Flight Flight Class related features Sensors Events labels Jun 15, 2026
@MateusStano MateusStano marked this pull request as draft June 15, 2026 17:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 thread rocketpy/utilities.py
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 thread rocketpy/rocket/rocket.py
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``.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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``.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New feature or request, including adjustments in current codes Events Flight Flight Class related features Parachute Related to parachutes methods and usage Refactor Sensors

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants