Body
BodyProxy Design Pattern
The simulation uses a Structure-of-Arrays (SoA) layout for its core physics data (implemented in the src.body.Bodies class) to maximize cache efficiency and enable highly vectorized computations with NumPy. While this is excellent for performance, directly manipulating individual body properties in an SoA can sometimes be less intuitive than an Array-of-Structures (AoS) approach, where each body is a distinct object with its own attributes.
To bridge this gap, the src.body.BodyProxy class implements the Proxy design pattern.
Purpose of BodyProxy:
The src.body.BodyProxy acts as a convenient, object-oriented wrapper around a single body’s data within the src.body.Bodies container. It provides an AoS-like interface, allowing developers to access and modify properties of an individual body (e.g., body.x for position, body.v for velocity) as if it were a standalone object.
How it Works:
Reference to SoA: Each
src.body.BodyProxyinstance holds a reference to the mainsrc.body.Bodiescontainer and the_indexof the specific body it represents.Property Accessors: All properties (like
m,r,x,v,q, etc.) are implemented as Python properties that directly access the corresponding slice of the NumPy arrays within thesrc.body.Bodiescontainer using the stored_index.Mutable Operations: Methods like
set_acceleration,accumulate_acceleration, andapply_impulsedirectly modify the underlying NumPy arrays in thesrc.body.Bodiescontainer at the specified index.
Benefits:
Readability and Ergonomics: Provides a more natural, object-oriented way to interact with individual bodies, improving code readability and developer experience.
Performance Preservation: Crucially, it does so without sacrificing the performance benefits of the underlying SoA layout, as the actual data remains contiguous and accessible for vectorized operations.
Encapsulation: It encapsulates the details of the SoA implementation, allowing the rest of the codebase to work with individual bodies more abstractly.
This pattern allows the simulation to leverage the best aspects of both data organization strategies: high-performance vectorized operations on the src.body.Bodies container and intuitive, object-oriented access to individual bodies via src.body.BodyProxy.
Module Overview

Provides a Structure-of-Arrays (SoA) container for simulation bodies and a proxy for Array-of-Structures (AoS)-like access.
The Bodies class uses an SoA layout (e.g., all masses in one array, all positions in another) for cache-efficient computations. The BodyProxy class provides a convenient AoS-like interface (body.x, body.v) for a single body, combining the best of both worlds.
- module:
body
- author:
Le Bars, Yoann
- class src.body.Bodies(n: int)[source]
Bases:
objectStructure-of-Arrays (SoA) container for all bodies in the simulation. This layout improves cache performance by storing related data contiguously.
- Variables:
m (np.ndarray) – Mass of each body.
inv_m (np.ndarray) – Inverse mass of each body.
r (np.ndarray) – Radius of each body.
i_inv (np.ndarray) – Inverse moment of inertia of each body.
x (np.ndarray) – Position of each body (n, 3).
v (np.ndarray) – Velocity of each body.
a (np.ndarray) – Acceleration of each body.
q (np.ndarray) – Orientation of each body.
omega (np.ndarray) – Angular velocity of each body.
alpha (np.ndarray) – Angular acceleration of each body.
torque (np.ndarray) – Net torque applied to each body in a frame.
_size (int) – Number of bodies.
- a: ndarray
- alpha: ndarray
- emplace_back(m: float, r: float, x0: ndarray, v0: ndarray) None[source]
Adds a new body to the data structure.
- Parameters:
m (float) – Body mass.
r (float) – Body radius.
x0 (np.ndarray) – Body position.
v0 (np.ndarray) – Body velocity.
- i_inv: ndarray
- integrate_part1(dt: float) None[source]
Velocity Verlet: Part 1 (Vectorised). Updates positions and half-updates velocities for all bodies.
- Parameters:
dt (float) – Time step.
- integrate_part2(dt: float) None[source]
Velocity Verlet: Part 2 (Vectorised). Completes the velocity updates for all bodies.
- Parameters:
dt (float) – Time step.
- inv_m: ndarray
- m: ndarray
- omega: ndarray
- q: ndarray
- r: ndarray
- torque: ndarray
- v: ndarray
- x: ndarray
- class src.body.BodyProxy(bodies: Bodies, index: int)[source]
Bases:
objectA proxy object that provides an AoS-like interface to a body stored in the Bodies SoA container.
The Bodies class uses a Structure-of-Arrays (SoA) layout for performance, where all positions are in one array, all velocities in another, etc. This is ideal for vectorised physics calculations.
However, it can be inconvenient to work with a single body’s properties. This BodyProxy class solves that problem by implementing the Proxy design pattern. It provides a classic Array-of-Structures (AoS) interface (e.g., body.x, body.v) for a single body, while the underlying data remains in the efficient SoA format. This gives us the best of both worlds: high-performance vectorised operations on the Bodies container and intuitive, object-oriented access to individual bodies.
- Variables:
_bodies (Bodies) – The main SoA container.
_index (int) – The index of the body this proxy refers to.
- property a: ndarray
Body acceleration.
- accumulate_acceleration(accel: ndarray) None[source]
Accumulate an acceleration.
- Parameters:
accel (np.ndarray) – Acceleration vector.
- accumulate_angular_acceleration(angular_accel: ndarray) None[source]
Accumulate an angular acceleration.
- Parameters:
angular_accel (np.ndarray) – Angular acceleration vector.
- accumulate_torque(torque_vec: ndarray) None[source]
Accumulate a torque vector.
- Parameters:
torque_vec (np.ndarray) – Torque vector to add.
- property alpha: ndarray
Body angular acceleration.
- apply_impulse(j_total: ndarray, r_vec: ndarray, epsilon: float) None[source]
Apply an impulse to the body, updating its linear and angular velocity based on the impulse-momentum theorem.
- Parameters:
j_total (np.ndarray) – Total impulse vector.
r_vec (np.ndarray) – Vector from the body’s centre of mass to the point of impulse application.
epsilon (float) – Small value to avoid division by zero.
- dampen_velocity(linear_damping: float, angular_damping: float) None[source]
Applies damping to linear and angular velocities to stabilise the simulation.
- Parameters:
linear_damping (float) – Damping factor for linear velocity.
angular_damping (float) – Damping factor for angular velocity.
- property i_inv: float
Inverse of the moment of inertia.
- property inv_m: float
Inverse of the body mass.
- property m: float
Body mass.
- property omega: ndarray
Body angular velocity.
- property q: Rotation
Body orientation.
- property r: float
Body radius.
- set_acceleration(new_a: ndarray) None[source]
Set the acceleration.
- Parameters:
new_a (np.ndarray) – New acceleration vector.
- property torque: ndarray
Net torque on the body for the current frame.
- property v: ndarray
Body velocity.
- property x: ndarray
Body position.