Theoretical Reference: Monoidal Forces Architecture
1. Philosophical Grounding
In classical mechanics, the principle of superposition states that the net force on an object is the vector sum of all individual forces. This physical law directly maps to the algebraic structure of a Monoid.
A Monoid for Forces requires:
- Binary Operation (Combine): An associative operation to sum two force/torque patches.
- Identity Element (Neutral): A "Zero Force" state where adding it to any force $F$ results in $F$.
By treating Forces as a Monoid, we align our software architecture with the underlying physics, enabling safer parallelization and better extensibility.
2. The Algebraic Structure
Identity ($\epsilon$)
Defined as Forces::zero(), where all vector components are zero and all scalar rates (mass flux) are zero.
Combination ($\oplus$)
For any two force patches $F_1$ and $F_2$: $$ F_{total} = F_1 \oplus F_2 $$ Implemented via operator+, which performs element-wise addition of forces, moments, gravity vectors, and mass flow rates.
3. Implementation Strategy (The 3-Layer Lift)
Layer 1: Monoid Definition
The Forces struct is upgraded from a simple data container to a Monoid by implementing operator+ and operator+=.
Layer 2: Functional Lifting
Since different physics kernels return different specialized types (e.g., ThrustAndMassFlux, ForceAndTorque), we use "Lift" functions to convert these into a unified Forces patch.
- Thrust Lift: Maps thrust vector and mass flux to a
Forcesobject. - Aero Lift: Maps aerodynamic force and moment to a
Forcesobject. - Gravity Lift: Maps gravity acceleration to the
gravity_licfield.
Layer 3: Monoidal Composition (mconcat)
The PhysicalRegistry utilizes an mconcat pattern to aggregate all force sources. This replaces nested lambda chains with a declarative list.
auto pipeline = mconcat_forces({
lift_thrust(engine_effects),
lift_aero(dyn_in),
lift_gravity()
});4. Design Benefits
a. Open-Closed Principle
Adding a new force source (e.g., Solar Radiation Pressure, Magnetic Torquers) no longer requires modifying the orchestration logic in PhysicalRegistry.cpp. One simply writes a new kernel and adds its "lifted" version to the mconcat list.
b. Parallelization via Associativity
Because Monoid addition is associative, the computation of force patches can be executed in parallel within a single Body's update cycle. The final result is guaranteed to be identical regardless of the calculation order, provided the kernels are side-effect free relative to the RocketBody state.
c. Mathematical Verifiability
The correctness of the force accumulation can be verified using algebraic properties (Identity law, Associativity law) in unit tests, independent of the actual physics values.
5. Constraints and Considerations
- Side Effects: Kernels must not modify the
RocketBodystate during the calculation phase to ensure parallel safety. - State Synchronization: Non-monoidal results (like individual engine operational states) must be handled through a secondary channel or a product monoid if order-dependency is required.
- Coordinate Rigor: All patches must be expressed in the same reference frame (usually the Body frame for forces/moments and the LIC frame for gravity) before being combined.