diff --git a/docs/find_dominant_body_bug.md b/docs/find_dominant_body_bug.md new file mode 100644 index 0000000..889ee25 --- /dev/null +++ b/docs/find_dominant_body_bug.md @@ -0,0 +1,77 @@ +# Find Dominant Body Bug: Mutual SOI Issue + +## Overview +This documents the remaining issue with `find_dominant_body()` when two similar-mass bodies are positioned within each other's sphere of influence (SOI). + +**Date:** January 20, 2026 +**Status:** Failing Test (Test 4 from test_plan_invalid_parent_assignment.md) +**Related:** `docs/test_plan_invalid_parent_assignment.md` + +--- + +## Test Case 4: Mutual SOI - Similar Mass Planets + +**Purpose:** Edge case: two Earth-like planets positioned within each other's SOI + +**Actual Result:** ❌ **STILL FAILS** (separate issue, not fixed by spacecraft validation) + +**Config:** `tests/configs/mutual_soi_close.toml` + +**Setup:** +- PlanetA: mass = 5.972e24 kg, position = {1.496e11, 0, 0} +- PlanetB: mass = 5.972e24 kg, position = {1.501e11, 0, 0} +- Separation: 5e8 meters (500 million km) +- Planet SOI: ~9.25e8 meters (925 million km) +- **Both planets within each other's SOI** + +**Why This Fails:** +- Both planets start with parent=0 (Sun) +- Both are within each other's SOI +- `find_dominant_body()` logic selects closest body within SOI +- Result: PlanetA selects PlanetB as parent, PlanetB selects PlanetA as parent +- Config validation passes (both are ≥ parent.radius + body.radius from Sun) + +**Key Assertions:** +```cpp +// Both should orbit Sun (not each other) +REQUIRE(sim->bodies[PLANET_A_IDX].parent_index == SUN_IDX); +REQUIRE(sim->bodies[PLANET_B_IDX].parent_index == SUN_IDX); + +// Planets should never have each other as parents +for (int parent : history.planet_a_parents) { + REQUIRE(parent != PLANET_B_IDX); +} +for (int parent : history.planet_b_parents) { + REQUIRE(parent != PLANET_A_IDX); +} +``` + +**Expected Behavior (Option A):** +- Both planets should continue orbiting Sun +- Neither should become other's parent +- This requires future fix to `find_dominant_body()` logic (mass hierarchy check) + +--- + +## Future Work + +### Current Status +Tests 1-3 from the parent assignment test suite are now passing. Test 4 continues to fail, documenting a separate mutual SOI issue. + +### Potential Fixes for Test 4 +1. Add mass hierarchy check to `find_dominant_body()` +2. Prevent mutual SOI assignments for similar-mass bodies +3. Detect and reject invalid configs at load time +4. Implement proper N-body interaction or restricted 3-body solution + +### Enhanced Detection +- SOI overlap detection at config load time +- Automatic correction of invalid parent assignments +- Validation warnings for edge cases + +--- + +## References +- `src/simulation.cpp:64-107` - `find_dominant_body()` implementation +- `tests/configs/mutual_soi_close.toml` - Test configuration for mutual SOI case +- `tests/test_invalid_parent_assignment.cpp` - Test suite implementation diff --git a/docs/mission_planning.md b/docs/mission_planning.md deleted file mode 100644 index 42eb0de..0000000 --- a/docs/mission_planning.md +++ /dev/null @@ -1,455 +0,0 @@ -# Implementation Plan: Config-Based Spacecraft with Impulse Burn - -## Overview -Replace dynamic spacecraft spawning with config-based LEO spacecraft, implement patched conics impulse burn for Hohmann transfer, and add comprehensive test verification. - -**Date:** January 18, 2026 -**Status:** partially implemented -**Branch:** mission-planning - ---- - -## Phase 1: Update Configuration File - -### Step 1.1: Add spacecraft to `tests/configs/earth_mars_simple.toml` - -Add Spacecraft body to config with placeholder position/velocity (set at runtime by `initialize_spacecraft_leo()`). - -**Implementation:** See `tests/configs/earth_mars_simple.toml` for full config - -**Key parameters:** -- mass = 1.0 kg (test particle) -- radius = 1000.0 m -- parent_index = 1 (Earth) -- color = magenta (r=1.0, g=0.0, b=0.5) -- position/velocity: Placeholders (0,0,0) - -**TODO**: Future config format should support: -- Earth-relative position: `{ altitude_km = 200.0 }` -- Earth-relative orbit: `{ orbit_type = "circular" }` -- More intuitive spacecraft mission parameters - ---- - -## Phase 2: Mission Planning Module - New Functions - -### Step 2.1: Add function declarations to `src/mission_planning.h` - -**Implementation:** See `src/mission_planning.h` - -**Functions:** -- `initialize_spacecraft_leo()` - Initialize spacecraft in circular LEO around parent body -- `apply_transfer_burn()` - Apply patched conics impulse burn for Hohmann transfer -- `calculate_phase_angle()` - Calculate current phase angle between two bodies (in degrees) - -### Step 2.2: Implement `initialize_spacecraft_leo()` in `src/mission_planning.cpp` - -**Implementation:** `src/mission_planning.cpp:20-56` - -**Algorithm:** -- Calculate orbital radius = parent radius + altitude -- Position spacecraft radially outward from Sun (any angular position acceptable) -- Calculate circular LEO velocity: v = sqrt(G * M_parent / r) -- Set prograde orientation (tangential to Earth-Sun line) -- Set both local and global coordinates correctly - -**Key Points:** -- LEO orbit is circular at 200km altitude (~7,788 m/s) -- Spacecraft velocity = Earth velocity + LEO velocity -- Local velocity = LEO velocity only (relative to Earth) - -### Step 2.3: Implement `calculate_phase_angle()` in `src/mission_planning.cpp` - -**Implementation:** `src/mission_planning.cpp:58-78` - -**Algorithm:** -- Calculate angular positions of departure and arrival bodies relative to Sun -- Compute phase difference: θ_arrival - θ_departure -- Normalize to [0°, 360°) range -- Return phase angle in degrees - -### Step 2.4: Implement `apply_transfer_burn()` in `src/mission_planning.cpp` - -**Implementation:** `src/mission_planning.cpp:80-116` - -**Algorithm (Patched Conics Approach):** -- Calculate required heliocentric transfer velocity magnitude from params -- Determine prograde direction (tangential to departure-Sun line) -- Compute delta-v: Δv = v_transfer - v_current (vector subtraction) -- Apply impulse to spacecraft velocity -- Update local velocity relative to departure body -- Print burn information for debugging - -**Note:** Simplified single-impulse approximation. True patched conics would: -1. Calculate Δv to reach SOI boundary -2. Calculate velocity at SOI boundary -3. Add transfer Δv at SOI boundary -4. Combine into equivalent single impulse - ---- - -## Phase 3: Comprehensive Test Case - -### Step 3.1: Create new test in `tests/test_hohmann_transfer.cpp` - -**Implementation:** `tests/test_hohmann_transfer.cpp` - See file for full test - -**Test:** "Earth → Mars Hohmann Transfer with LEO Spacecraft" - -**Test Structure:** -1. Load config with 4 bodies (Sun, Earth, Mars, Spacecraft) -2. Initialize spacecraft in 200km LEO around Earth -3. Verify LEO orbit stability (parent, position, velocity, energy) -4. Calculate Hohmann transfer parameters -5. Wait for Earth-Mars launch window (within 1° tolerance) -6. Verify phase angle accuracy -7. Apply impulse burn for transfer -8. Verify post-burn energy >= 0 (escape trajectory) -9. Simulate transfer for 110% of expected duration -10. Track SOI transitions (Earth→Sun→Mars) -11. Verify final parent and energy conservation (<5% drift) -12. If Mars SOI entry, verify distance (<2×SOI) - -**Key Assertions:** -- Config loading: 4 bodies loaded, spacecraft present -- LEO stability: parent=Earth, position <1km error, velocity <10m/s error, energy <0 -- Launch window: opens in ~94 days, phase error <1° -- Transfer: post-burn energy >= 0, Earth→Sun SOI transition, energy conservation - ---- - -## Current Issue Identified - -### Problem: Incorrect Delta-V Direction After Multi-Day Wait - -**RESOLVED (Jan 20, 2026):** - -The FIXME issue below has been addressed by adding config validation in -`src/config_loader.cpp` that prevents bodies from starting too close to their -parent bodies. The spacecraft configuration has been corrected to use proper LEO -altitude (200km) instead of placeholder values. - -**Solution Applied:** -- Config validation: distance ≥ parent.radius + body.radius -- Spacecraft position corrected to 1.49606571e11 m (Earth + 6,571 km offset) -- Tests 1-3 in `test_invalid_parent_assignment.cpp` now pass - -**FIXME (Original Issue - RESOLVED):** - While running this simulation config graphically, I noticed that a larger - problem is in simulation::find_dominant_body(). Earth's parent gets set to - the satellite's index, which should never happen. - I think the actual fix should be to have non-massive satellites in a different - array than celestial bodies, and treat them differently. - However, we should add more testing for the case that a comet or other massive - celestial body gets close to another body. - We do have tests/test_soi_transition.cpp, and tests/configs/soi_transition.toml - so maybe it's an initialization problem because the new test config starts - with both bodies in each others SOI? - -**Symptom:** -- Spacecraft enters LEO orbit correctly with negative energy (bound to Earth) -- Waits 94 days for Earth-Mars launch window -- During wait period, spacecraft completes ~6.3 LEO orbits -- LEO orbit phase changes significantly over 94 days -- After wait, `apply_transfer_burn()` applies delta-v assuming spacecraft is at Earth's current orbital phase -- Result: Delta-v applied in wrong direction, resulting in retrograde burn -- Post-burn energy remains negative (spacecraft still bound to Earth) - -**Root Cause Analysis:** - -The `apply_transfer_burn()` function calculates: -1. Required heliocentric transfer velocity magnitude: `v_transfer = 32,697 m/s` -2. Prograde direction based on Earth's current position: `transfer_dir = prograde(t_current)` -3. Target velocity: `v_target = v_transfer * transfer_dir` - -However, after 94 days: -- Earth has moved to different orbital phase -- Spacecraft in LEO is still orbiting Earth -- Spacecraft's current heliocentric velocity includes Earth's motion + LEO motion -- The calculated transfer direction is based on Earth's instantaneous position, not spacecraft's actual heliocentric velocity vector -- This results in delta-v that doesn't account for spacecraft's phase in LEO - -**What Should Happen:** -1. Calculate spacecraft's current heliocentric velocity vector: `v_current` -2. Calculate required heliocentric velocity for transfer orbit: `v_transfer` -3. Apply delta-v: `Δv = v_transfer - v_current` (vector subtraction, not magnitude-based) - -**What Currently Happens:** -1. Assumes spacecraft starts at Earth's orbital position (ignores LEO phase) -2. Calculates transfer direction based on Earth's current prograde vector -3. Applies magnitude-based delta-v without considering spacecraft's actual velocity direction -4. Results in incorrect burn direction - -### Solution Required (Pending) - -NOTE: The immediate bug of Earth becoming a child of spacecraft has been -resolved by config validation. The delta-v calculation issue below remains for -future implementation. - -Modify `apply_transfer_burn()` to: - -1. **Calculate spacecraft's actual heliocentric velocity:** -```cpp -Vec3 v_current_helio = spacecraft->velocity; // Already in global frame -``` - -2. **Calculate required heliocentric transfer velocity:** -```cpp -double v_transfer_mag = params->departure_velocity; // ~32,697 m/s - -// Direction: prograde to Sun (same as Earth's orbital direction) -Vec3 sun_to_earth = vec3_sub(departure->position, sun->position); -Vec3 sun_to_earth_norm = vec3_normalize(sun_to_earth); -Vec3 transfer_dir = (Vec3){-sun_to_earth_norm.y, sun_to_earth_norm.x, 0.0}; -Vec3 v_transfer_helio = vec3_scale(transfer_dir, v_transfer_mag); -``` - -3. **Calculate delta-v as vector difference:** -```cpp -Vec3 delta_v = vec3_sub(v_transfer_helio, v_current_helio); -``` - -4. **Apply impulse:** -```cpp -spacecraft->velocity = vec3_add(spacecraft->velocity, delta_v); -spacecraft->local_velocity = vec3_sub(spacecraft->velocity, departure->velocity); -``` - -**This approach:** -- Accounts for spacecraft's actual heliocentric velocity (includes LEO phase) -- Uses vector subtraction instead of magnitude-based calculation -- Produces correct delta-v direction regardless of LEO phase -- Should result in positive post-burn energy (escape trajectory) - ---- - -## Potential Issues and Mitigation - -### Issue 1: LEO Orbit Position Sensitivity -Spacecraft LEO phase may affect optimal launch window timing. - -**Mitigation**: Test shows we wait for Earth-Mars phase angle, not spacecraft-LEO phase. This should be acceptable. - -### Issue 2: Impulse Burn Accuracy -Single-impulse approximation may not match true patched conics trajectory. - -**Mitigation**: Initial test focuses on Earth→Sun transition and energy conservation. If needed, can refine to two-impulse burn in future. - -### Issue 3: Mars SOI Entry -Spacecraft may not enter Mars SOI due to: -- Phase angle tolerance (1°) -- Transfer time approximation -- Impulse burn simplifications - -**Mitigation**: Test includes explicit INFO messages and requires only Earth→Sun transition, not Mars arrival. - ---- - -## Timeline Estimate - -- Phase 0 (Git workflow): 10 minutes -- Phase 1 (Config update): 5 minutes -- Phase 2 (Mission planning): 1-2 hours -- Phase 3 (Comprehensive test): 30 minutes -- Phase 4 (Build and test): 20 minutes -- Phase 5 (Cleanup): 20 minutes - -**Total**: 2-3 hours - ---- - -## Test Configuration Reference - -### earth_mars_simple.toml -**Implementation:** `tests/configs/earth_mars_simple.toml` - -**Bodies:** -- Sun (index 0): Root body, 1.989e30 kg -- Earth (index 1): 5.972e24 kg, 1.496e11 m from Sun -- Mars (index 2): 6.39e23 kg, 2.279e11 m from Sun -- Spacecraft (index 3): 1.0 kg, parent=Earth (position specified in config) - -**Spacecraft parameters:** -- mass = 1.0 kg -- radius = 1000.0 m -- parent_index = 1 (Earth) -- color = magenta (r=1.0, g=0.0, b=0.5) -- position: 1.49606571e11 m (Earth position + 6,571,000 m LEO offset) -- velocity: Calculated by `initialize_bodies()` using `semi_major_axis = 6.571e6` - ---- - -## Future Work (Post-Implementation) - -### Immediate Next Steps - -**TODO: Spacecraft Config Pattern Changes** - -Spacecraft now requires full position specification in config files: -- Removed placeholder pattern that expected `initialize_spacecraft_leo()` to set position at runtime -- Position must be: parent position + orbital altitude offset -- Example: Earth LEO at 200km = Earth radius (6.371e6 m) + 200,000 m = 6.571e6 m offset -- Velocity is calculated by `initialize_bodies()` using `semi_major_axis` parameter - -**Impact on `initialize_spacecraft_leo()`:** -- Currently sets position relative to parent -- May need to be deprecated or updated to validate/override config-based positions -- Consider keeping function for dynamic scenarios (e.g., multi-burn missions) - -#### 1. Config Format Improvements -- Support Earth-relative position specification (e.g., `{ altitude_km = 200.0 }`) -- Support Earth-relative orbit specification (e.g., `{ orbit_type = "circular" }`) -- More intuitive spacecraft mission parameters in TOML config -- Support multiple spacecraft in single config file - -#### 2. Improved Patched Conics Implementation -- Calculate Δv to reach SOI boundary (escape trajectory) -- Calculate velocity at SOI boundary -- Add transfer Δv at SOI boundary -- Combine into equivalent single impulse -- Test accuracy of two-impulse vs single-impulse approach - -#### 3. Inclination Support -- Extend to 3D transfers -- Need 3D angular position calculations -- Longitude of ascending node, inclination, argument of periapsis -- Phase angle calculations in 3D -- Out-of-plane maneuver calculations - -#### 4. Capture Burns -- Simulate retrograde burns for orbital capture at destination -- Calculate Δv needed for circularization -- Support parking orbits at arrival body -- Validate Mars capture burns (~1.4 km/s for Mars) - -#### 5. Adaptive Timestepping - -**Problem:** Fixed 60s timestep is: -- Too coarse for fast orbital phases (moon capture, close approaches) -- Too slow for deep-space phases (interplanetary transfers) - -**Solution:** Adaptive timestep based on orbital period - -**Implementation:** -```cpp -double calculate_adaptive_timestep(CelestialBody* body, CelestialBody* parent) { - if (parent == NULL || body->semi_major_axis <= 0.0) { - return 60.0; // Default timestep - } - - // Calculate orbital period using Kepler's third law - double T = 2.0 * M_PI * sqrt(pow(body->semi_major_axis, 3) / (G * parent->mass)); - - // Use 1/1000 of orbital period as timestep - double adaptive_dt = T / 1000.0; - - // Clamp to reasonable bounds - adaptive_dt = fmax(adaptive_dt, 10.0); // Minimum 10s - adaptive_dt = fmin(adaptive_dt, 600.0); // Maximum 600s - - return adaptive_dt; -} -``` - -**Changes required:** -- Add per-body timesteps to `SimulationState` -- Update `update_simulation()` to use adaptive timesteps -- Add synchronization mechanism for multiple timesteps - -**Expected outcome:** -- Better accuracy for fast orbits (moon capture) -- Faster simulation for deep-space phases -- Energy conserved across SOI transitions - -**Tests:** -- Verify energy drift with adaptive timesteps -- Verify orbital period accuracy with adaptive timesteps -- Test stability across SOI transitions - -### Visualization Features - -#### 6. Mission GUI -- Interactive departure window visualization -- Show current phase angle vs. required phase angle -- Countdown to launch window -- Transfer trajectory preview (predicted path) -- Delta-v budget display - -#### 7. Multiple Burns Support -- Mid-course corrections -- Gravity assist maneuvers -- Powered flybys -- Multi-stage missions - -#### 8. SOI Visualization -- Render SOI boundaries as wireframe spheres -- Color-coded by mass -- Toggle with keyboard shortcut -- Show SOI transitions in real-time - -### Advanced Features - -#### 9. Mission Planner -- Complete mission design tool -- Multi-leg missions (Earth→Mars→Phobos) -- Optimization algorithms (minimum Δv, minimum time) -- Launch date search across windows -- Mission timeline visualization - -#### 10. Real Ephemeris Integration -- Use actual planetary positions (JPL Horizons API) -- Date-based initialization -- Real mission planning with actual ephemeris data -- Compare simulation to historical missions - -#### 11. Enhanced Trajectory Analysis -- Lambert solver for general transfers -- Not just Hohmann transfers -- Arbitrary departure/arrival positions and times -- Non-planar transfers - ---- - -## Notes - -### Coordinate System -- All calculations assume planar motion (z = 0) for initial implementation -- Angular positions measured in XY plane -- Future work: Extend to 3D with inclination - -### Timekeeping -- Simulation time in seconds, conversions to days for display -- Fast-forward uses 1-day steps for efficiency during launch window wait -- Timestep remains 60s during fast-forward - -### Mass Strategy -- Spacecraft mass = 1.0 kg (negligible but non-zero) -- Physics engine handles test particles correctly (mass cancels in acceleration) -- No N-body perturbations from spacecraft on planetary bodies - -### Validation Strategy -- Compare against NASA reference missions (Viking, Curiosity, Perseverance) -- Energy conservation tracking during transfer -- Transfer time accuracy (±10% tolerance) -- SOI transition verification (Earth→Sun→Mars) - -### Testing Approach -- Unit tests for each function (formulas, calculations) -- Integration tests for full missions (LEO initialization, impulse burn, transfer) -- Regression tests against expected Hohmann transfer parameters - -### LEO Orbit Considerations -- LEO orbit at 200 km altitude (r = 6.571×10⁶ m) -- LEO velocity: ~7,788 m/s at 200 km -- LEO period: ~88.5 minutes -- Spacecraft LEO phase changes significantly during multi-day wait periods -- Transfer burn must account for spacecraft's actual heliocentric velocity (not just Earth's) - ---- - -## References - -- `docs/implementation_plan.md` - Overall system architecture -- NASA Technical Memorandum "Hohmann Transfer Calculations" -- Orbital Mechanics for Engineering Students (Curtis) -- Fundamentals of Astrodynamics (Bate, Mueller, White) diff --git a/docs/test_plan_invalid_parent_assignment.md b/docs/test_plan_invalid_parent_assignment.md deleted file mode 100644 index fd3397e..0000000 --- a/docs/test_plan_invalid_parent_assignment.md +++ /dev/null @@ -1,240 +0,0 @@ -# Test Plan: Invalid Parent Assignment Bug - -## Overview -Comprehensive test suite to capture and validate parent-child relationship bugs in orbital mechanics simulation. - -**Date:** January 20, 2026 -**Status:** Complete (Tests 1-3 resolved) -**Related:** `docs/mission_planning.md` FIXME section - ---- - -## Bug Diagnosis - -### Root Cause Identified - -**The Bug (Fixed):** In `tests/configs/earth_mars_simple.toml`, spacecraft had placeholder values: -- `position = {1.496e11, 0, 0}` (IDENTICAL to Earth) -- `velocity = {0, 0, 0}` (zero velocity) -- `SOI = ~17.3 meters` (calculated from mass=1kg) - -**What Happened:** -1. Config loaded with spacecraft at Earth's exact position -2. During `find_dominant_body(1)` for Earth: - - Checks all bodies - - Finds spacecraft at distance = 0 - - `0 < 17.3` is TRUE - - Sets Earth's parent to spacecraft! - -**Why Test Failed But GUI Failed Worse:** -- Test calls `initialize_spacecraft_leo()` → spacecraft moved to proper LEO orbit (200km from Earth) -- GUI never called this → placeholder values caused immediate bug - -### Solution Implemented - -**Config Validation in `src/config_loader.cpp`:** -- Added validation loop after parsing bodies, before `initialize_bodies()` -- Validates that distance between body and parent ≥ parent.radius + body.radius -- Provides clear error message with actual and required distances -- Prevents loading invalid configs with bodies too close to their parents - -**Config Fix in `tests/configs/earth_mars_simple.toml`:** -- Changed spacecraft position from `1.496e11` (same as Earth) to `1.49606571e11` -- This places spacecraft at proper LEO altitude: Earth position + 6,571,000 m -- 6,571 km = Earth radius (6,371 km) + 200 km altitude - ---- - -## Test Cases - -### Test Case 1: Earth→Spacecraft Parent Switch - -**Purpose:** Directly detect when Earth's parent becomes spacecraft (the exact bug from FIXME) - -**Actual Result:** ✅ **PASSES** - -**How It Was Fixed:** -- Config validation now rejects bodies starting at parent's position -- Spacecraft properly positioned at LEO altitude (6,571 km from Earth center) -- `find_dominant_body()` never finds spacecraft at distance=0 -- Earth's parent remains Sun throughout simulation - -**Config:** `tests/configs/earth_mars_simple.toml` - -**Key Assertion:** -```cpp -REQUIRE(sim->bodies[EARTH_IDX].parent_index != SPACECRAFT_IDX); -``` - ---- - -### Test Case 2: Mass Hierarchy Validation - -**Purpose:** Validate that massive bodies never become children of small bodies - -**Actual Result:** ✅ **PASSES** - -**How It Was Fixed:** -- Config validation ensures proper parent-child distance -- Mass hierarchy preserved throughout simulation -- Earth never becomes child of spacecraft or other bodies - -**Config:** `tests/configs/earth_mars_simple.toml` - -**Key Assertions:** -```cpp -// Parent must be more massive -REQUIRE(mass_ratio >= 1.0); - -// For planets: parent should be significantly more massive -if (not spacecraft) { - REQUIRE(mass_ratio >= 1000.0); -} - -// Massive bodies should never have small bodies as parents -if (child_mass > 1e20) { // Planet-scale - REQUIRE(parent_mass > child_mass); -} -``` - ---- - -### Test Case 3: Config Placeholder Validation - -**Purpose:** Detect invalid config initialization (bodies starting too close together) - -**Actual Result:** ✅ **PASSES** - -**How It Was Fixed:** -- Test updated to use radius-based validation (matches config_loader logic) -- Spacecraft now at proper LEO position: 6,571,000 m from Earth center -- Validation: distance (6,571,000 m) ≥ Earth.radius + spacecraft.radius (6,372,000 m) -- Config validation catches any bodies positioned within parent's radius - -**Config:** `tests/configs/earth_mars_simple.toml` - -**Key Assertion:** -```cpp -double min_distance = sim->bodies[EARTH_IDX].radius + sim->bodies[SPACECRAFT_IDX].radius; -REQUIRE(distance >= min_distance); // parent.radius + body.radius -``` - ---- - -### Test Case 4: Mutual SOI - Similar Mass Planets - -**Purpose:** Edge case: two Earth-like planets positioned within each other's SOI - -**Actual Result:** ❌ **STILL FAILS** (separate issue, not fixed by spacecraft validation) - -**Config:** `tests/configs/mutual_soi_close.toml` - -**Setup:** -- PlanetA: mass = 5.972e24 kg, position = {1.496e11, 0, 0} -- PlanetB: mass = 5.972e24 kg, position = {1.501e11, 0, 0} -- Separation: 5e8 meters (500 million km) -- Planet SOI: ~9.25e8 meters (925 million km) -- **Both planets within each other's SOI** - -**Why This Fails:** -- Both planets start with parent=0 (Sun) -- Both are within each other's SOI -- `find_dominant_body()` logic selects closest body within SOI -- Result: PlanetA selects PlanetB as parent, PlanetB selects PlanetA as parent -- Config validation passes (both are ≥ parent.radius + body.radius from Sun) - -**Key Assertions:** -```cpp -// Both should orbit Sun (not each other) -REQUIRE(sim->bodies[PLANET_A_IDX].parent_index == SUN_IDX); -REQUIRE(sim->bodies[PLANET_B_IDX].parent_index == SUN_IDX); - -// Planets should never have each other as parents -for (int parent : history.planet_a_parents) { - REQUIRE(parent != PLANET_B_IDX); -} -for (int parent : history.planet_b_parents) { - REQUIRE(parent != PLANET_A_IDX); -} -``` - -**Expected Behavior (Option A):** -- Both planets should continue orbiting Sun -- Neither should become other's parent -- This requires future fix to `find_dominant_body()` logic (mass hierarchy check) - ---- - -## Test Matrix - -| Test Case | Config | Tests | Expected (Before Fix) | **Actual Result** | -|-----------|--------|-------|----------------------|--------------------------------| -| **1. Earth→Spacecraft** | earth_mars_simple.toml | Parent assignment | **FAIL** | **✅ PASS** | -| **2. Mass Hierarchy** | earth_mars_simple.toml | Mass ratios | **FAIL** | **✅ PASS** | -| **3. Config Validation** | earth_mars_simple.toml | Separation distance | **FAIL** | **✅ PASS** | -| **4. Mutual SOI** | mutual_soi_close.toml | Edge case behavior | **FAIL** | **❌ FAIL** (separate issue) | - ---- - -## Implementation - -### Test File -`tests/test_invalid_parent_assignment.cpp` - -### Test Config Files -- `tests/configs/earth_mars_simple.toml` (existing) -- `tests/configs/mutual_soi_close.toml` (new) - -### Build Integration -Add to CMakeLists.txt or Makefile test targets - ---- - -## Implementation Summary - -**Solution Applied (Jan 20, 2026):** -1. **Config validation in `src/config_loader.cpp`**: - - Validates parent-child distances before initialization - - Requires distance ≥ parent.radius + body.radius - - Prevents loading invalid configs - -2. **Config fix in `tests/configs/earth_mars_simple.toml`**: - - Spacecraft position corrected to proper LEO altitude - - Position: 1.49606571e11 m (Earth position + 6,571,000 m offset) - - Velocity calculated by `initialize_bodies()` using `semi_major_axis = 6.571e6` - -3. **Test updates in `tests/test_invalid_parent_assignment.cpp`**: - - Test 3 updated to use radius-based validation - - Matches config_loader validation logic - ---- - -## Future Work - -### Current Status -Tests 1-3 are now passing. Test 4 continues to fail, documenting a separate mutual SOI issue. - -### Potential Fixes for Test 4 -1. Add mass hierarchy check to `find_dominant_body()` -2. Prevent mutual SOI assignments for similar-mass bodies -3. Detect and reject invalid configs at load time -4. Implement proper N-body interaction or restricted 3-body solution - -### Enhanced Detection -- SOI overlap detection at config load time -- Automatic correction of invalid parent assignments -- Validation warnings for edge cases - ---- - -## References -- `docs/mission_planning.md:125-135` - FIXME section describing bug (now resolved) -- `src/config_loader.cpp:138-157` - Config validation implementation -- `tests/configs/earth_mars_simple.toml` - Corrected spacecraft position (LEO altitude) -- `src/simulation.cpp:64-107` - `find_dominant_body()` implementation -- `src/simulation.cpp:212-233` - `initialize_bodies()` implementation -- `tests/test_invalid_parent_assignment.cpp` - Test suite implementation - -## Commits -- `0239cc1` - Add test suite for invalid parent assignment bugs -- `899fa3b` - Add config validation for parent-child distances