Proposal: Migrate the 6-DOF Simulation Core to Rust for Next-Level Performance
Context and Motivation
Recent PRs (like the excellent #1049) have drastically optimized our Function class, but as noted in the benchmarks, the overall simulation speedup is fundamentally bounded by the architecture.
If we profile a typical RocketPy simulation, the major bottleneck is the "boundary crossing" between Python and the underlying ODE solver (like scipy's LSODA). Every time the solver takes a step, it must acquire the Python GIL, convert arrays, and call our Python-based u_dot_generalized (and aerodynamic lookups) thousands of times per flight second.
To break this barrier and achieve orders-of-magnitude speedups, we need to remove the Python interpreter from the hot path entirely.
Proposal: The "Shell and Engine" Architecture
I propose we explore migrating the core mathematical and physical models to Rust, while keeping the user-friendly Python API exactly as it is.
We would adopt a hybrid architecture:
- The Python Shell (
rocketpy): Continues handling the user API, object parsing, file reading, matplotlib plotting, and printing.
- The Rust Engine (
rocketpy-core / _rocketpy_rs): A pure-math backend handling the 6-DOF equations of motion, rotation matrices, aerodynamic interpolations, and the numerical integration loop.
When a user calls Flight(...), the Python shell extracts the raw numbers/arrays from the Python objects and hands them to a single Rust function. Rust takes over, runs the entire flight integration instantly (without the GIL), and returns the final trajectory array back to Python for plotting.
Why Rust? (vs. C++ or Cython)
The Python ecosystem is undergoing a massive shift towards Rust. Major projects like Pydantic (V2), Ruff, Polars, and Cryptography have all recently migrated their cores to Rust. The advantages are clear:
- Zero-Setup Cross-Platform Builds: Dealing with MSVC/GCC/Clang compilation across Windows/Linux/macOS in C++ is famously painful. Rust’s
cargo and the Python tool Maturin make cross-platform wheel building in GitHub Actions almost effortless.
- The
pip install Experience: Users will simply run pip install rocketpy. They will download pre-compiled .whl binaries and will not need any Rust compiler installed on their machines.
- Memory Safety: If it compiles in Rust, it is virtually immune to the Segmentation Faults and memory leaks that haunt C/Cython extensions.
- PyO3: The PyO3 crate provides an incredibly elegant and safe way to write Python bindings.
A Pragmatic Approach to Numerical Integrators (Keeping LSODA)
One valid concern is losing SciPy's robust LSODA solver and its automatic stiff/non-stiff adaptive time-stepping. Rewriting LSODA from scratch in pure Rust would be an enormous, error-prone academic exercise.
Instead, the most pragmatic engineering approach is to migrate our equations of motion to Rust, and wrap an existing, battle-tested C-implementation of LSODA using Rust's FFI.
By using Rust's build.rs and the cc crate, we can automatically compile a C-version of LSODA alongside our Rust code during the wheel-building process. This means our pure-Rust physics engine can call the C-based LSODA solver in nanoseconds without ever touching the Python GIL. We get the safety and speed of Rust, the maturity of LSODA, and the user still just runs pip install rocketpy seamlessly.
Massive Impact on Monte Carlo (Dispersion)
Currently, our Monte Carlo analysis relies on Python's multiprocessing, which incurs heavy overhead (process spawning, memory duplication, pickle serialization).
By migrating to Rust, we unlock true multithreading. We could eventually pass a list of 10,000 flight parameters to Rust, and using crates like Rayon, run the simulations concurrently across all CPU cores with zero Python overhead. This would make dispersion analysis nearly instantaneous.
Proposed Phased Approach
We shouldn't rewrite everything at once. A safe migration path could be:
- Phase 1 (Proof of Concept): Set up a
maturin project workspace. Write a simple 2D ballistic trajectory integrator in Rust, import it into Python, and benchmark it against our current SciPy implementation to validate the speedup.
- Phase 2 (Core Migration): Migrate
u_dot_generalized and aerodynamic lookups to Rust. Bind it to a wrapped C-based LSODA solver via FFI.
- Phase 3 (Monte Carlo): Expose a vectorized/multithreaded entry point in Rust specifically for dispersion analysis.
Proposal: Migrate the 6-DOF Simulation Core to Rust for Next-Level Performance
Context and Motivation
Recent PRs (like the excellent #1049) have drastically optimized our
Functionclass, but as noted in the benchmarks, the overall simulation speedup is fundamentally bounded by the architecture.If we profile a typical RocketPy simulation, the major bottleneck is the "boundary crossing" between Python and the underlying ODE solver (like
scipy's LSODA). Every time the solver takes a step, it must acquire the Python GIL, convert arrays, and call our Python-basedu_dot_generalized(and aerodynamic lookups) thousands of times per flight second.To break this barrier and achieve orders-of-magnitude speedups, we need to remove the Python interpreter from the hot path entirely.
Proposal: The "Shell and Engine" Architecture
I propose we explore migrating the core mathematical and physical models to Rust, while keeping the user-friendly Python API exactly as it is.
We would adopt a hybrid architecture:
rocketpy): Continues handling the user API, object parsing, file reading,matplotlibplotting, and printing.rocketpy-core/_rocketpy_rs): A pure-math backend handling the 6-DOF equations of motion, rotation matrices, aerodynamic interpolations, and the numerical integration loop.When a user calls
Flight(...), the Python shell extracts the raw numbers/arrays from the Python objects and hands them to a single Rust function. Rust takes over, runs the entire flight integration instantly (without the GIL), and returns the final trajectory array back to Python for plotting.Why Rust? (vs. C++ or Cython)
The Python ecosystem is undergoing a massive shift towards Rust. Major projects like Pydantic (V2), Ruff, Polars, and Cryptography have all recently migrated their cores to Rust. The advantages are clear:
cargoand the Python tool Maturin make cross-platform wheel building in GitHub Actions almost effortless.pip installExperience: Users will simply runpip install rocketpy. They will download pre-compiled.whlbinaries and will not need any Rust compiler installed on their machines.A Pragmatic Approach to Numerical Integrators (Keeping LSODA)
One valid concern is losing SciPy's robust LSODA solver and its automatic stiff/non-stiff adaptive time-stepping. Rewriting LSODA from scratch in pure Rust would be an enormous, error-prone academic exercise.
Instead, the most pragmatic engineering approach is to migrate our equations of motion to Rust, and wrap an existing, battle-tested C-implementation of LSODA using Rust's FFI.
By using Rust's
build.rsand thecccrate, we can automatically compile a C-version of LSODA alongside our Rust code during the wheel-building process. This means our pure-Rust physics engine can call the C-based LSODA solver in nanoseconds without ever touching the Python GIL. We get the safety and speed of Rust, the maturity of LSODA, and the user still just runspip install rocketpyseamlessly.Massive Impact on Monte Carlo (Dispersion)
Currently, our Monte Carlo analysis relies on Python's
multiprocessing, which incurs heavy overhead (process spawning, memory duplication, pickle serialization).By migrating to Rust, we unlock true multithreading. We could eventually pass a list of 10,000 flight parameters to Rust, and using crates like
Rayon, run the simulations concurrently across all CPU cores with zero Python overhead. This would make dispersion analysis nearly instantaneous.Proposed Phased Approach
We shouldn't rewrite everything at once. A safe migration path could be:
maturinproject workspace. Write a simple 2D ballistic trajectory integrator in Rust, import it into Python, and benchmark it against our current SciPy implementation to validate the speedup.u_dot_generalizedand aerodynamic lookups to Rust. Bind it to a wrapped C-based LSODA solver via FFI.