From fdd4ec30409ec1908d1ea37b39b7dd0d6b191d5f Mon Sep 17 00:00:00 2001 From: cinnaboot Date: Mon, 19 Jan 2026 11:09:15 -0500 Subject: [PATCH] Add adaptive timestepping to mission planning and remove obsolete patched_conics_plan - Extract adaptive timestepping section from patched_conics_plan.md - Add to mission_planning.md Future Work section (after Capture Burns) - Problem: Fixed 60s timestep too coarse/fast for different orbital phases - Solution: Adaptive timestep based on orbital period using Kepler's third law - Implementation: calculate_adaptive_timestep() with 10s-600s clamping - Delete obsolete patched_conics_plan.md (689 lines, superseded by implementation) - Renumber sections 5-11 to accommodate new section 5 - Net reduction: ~645 lines of documentation --- docs/mission_planning.md | 56 ++- docs/patched_conics_plan.md | 688 ------------------------------------ 2 files changed, 50 insertions(+), 694 deletions(-) delete mode 100644 docs/patched_conics_plan.md diff --git a/docs/mission_planning.md b/docs/mission_planning.md index 54e146e..f2bc345 100644 --- a/docs/mission_planning.md +++ b/docs/mission_planning.md @@ -370,22 +370,66 @@ Spacecraft may not enter Mars SOI due to: - 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 -#### 5. Mission GUI +#### 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 -#### 6. Multiple Burns Support +#### 7. Multiple Burns Support - Mid-course corrections - Gravity assist maneuvers - Powered flybys - Multi-stage missions -#### 7. SOI Visualization +#### 8. SOI Visualization - Render SOI boundaries as wireframe spheres - Color-coded by mass - Toggle with keyboard shortcut @@ -393,20 +437,20 @@ Spacecraft may not enter Mars SOI due to: ### Advanced Features -#### 8. Mission Planner +#### 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 -#### 9. Real Ephemeris Integration +#### 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 -#### 10. Enhanced Trajectory Analysis +#### 11. Enhanced Trajectory Analysis - Lambert solver for general transfers - Not just Hohmann transfers - Arbitrary departure/arrival positions and times diff --git a/docs/patched_conics_plan.md b/docs/patched_conics_plan.md deleted file mode 100644 index fbd554e..0000000 --- a/docs/patched_conics_plan.md +++ /dev/null @@ -1,688 +0,0 @@ -# Patched Conics and SOI Transition Implementation Plan - -**Date:** January 14, 2026 -**Status:** Implementation Ready (Decisions Made) -**Branch:** patched-conics - -**Decisions Made:** -1. ✅ Hysteresis: Adaptive approach (Option B) -2. ✅ Integration timing: Current approach (Option A), TODO for future -3. ✅ Test priorities: Create all 3 test cases first -4. ✅ Adaptive timesteps: Deferred to later work (Phase 5) - -**Next Step:** Begin Phase 1 - Fix Root Body Transitions - -## Overview - -This plan implements support for patched conics trajectory simulation, enabling satellites to transition between multiple spheres of influence (SOI) in complex orbital scenarios: -- Planet → Star → Planet transfers -- Star → Planet → Moon rendezvous -- Multi-leg interplanetary missions - -## Current State Analysis - -### ✅ What's Already Working - -1. **SOI Transitions Are Already Implemented** - - Lines 103-121 in `simulation.cpp` show coordinate transformation logic - - Converts local→global using old parent, then global→local using new parent - - This is essentially Phase 3 implementation from hierarchical_frames_plan.md - -2. **Local Frame Integration** (Phase 2) ✅ - - All bodies integrate in local coordinates - - Global coordinates computed after each timestep - - Improved numerical precision for nested orbits - -3. **Parent-First Update Order** (Phase 4) ✅ - - Root bodies skipped in loop (fixed at origin) - - Child bodies integrate using parent coordinates - - Hierarchical update order implemented - -### 🔴 Critical Issues for Patched Conics - -**Issue 1: Cannot Transition to Root Bodies** -```cpp -if (new_parent != body->parent_index && new_parent != -1) { - // ... transition logic -} -``` -The `new_parent != -1` condition prevents switching to Sun (parent_index = -1). This breaks the scenario: Planet→Sun→Moon rendezvous is impossible. - -**Issue 2: Hysteresis Barrier** -The 0.5x hysteresis factor in `find_dominant_body()` (line 71) creates one-way barriers: -- Planet→Sun: Possible (easy entry) -- Sun→Planet: **Impossible** (can't exit due to hysteresis) - -**Issue 3: Integration After Transition** -Transition happens before integration in the same timestep, using coordinates from the end of the previous timestep. This may cause velocity discontinuities. - -### ⚠️ Potential Issues - -**Issue 4: Numerical Precision** -Satellites crossing between star/planet/moon scales will see position magnitude changes of 10⁸ to 10¹¹ meters, potentially losing precision. - -**Issue 5: Fixed Timestep** -60s timestep may be too coarse for fast orbital phases (moon capture) and too slow for deep-space phases. - -## Implementation Phases - -### Phase 1: Fix Root Body Transitions (Critical) - -**Goal:** Allow satellites to switch to/from Sun (parent_index = -1) - -**Changes:** -1. Remove `new_parent != -1` check in `simulation.cpp` line 104 -2. Add special handling for root body transitions: - ```cpp - if (new_parent != body->parent_index) { - // Convert local → global using old parent - if (body->parent_index >= 0) { - // old_parent is a real body - CelestialBody* old_parent = &sim->bodies[body->parent_index]; - body->position = vec3_add(body->local_position, old_parent->position); - body->velocity = vec3_add(body->local_velocity, old_parent->velocity); - } else { - // old_parent is root (Sun): local = global - body->position = body->local_position; - body->velocity = body->local_velocity; - } - - body->parent_index = new_parent; - - // Convert global → local using new parent - if (new_parent >= 0) { - // new_parent is a real body - CelestialBody* new_parent_body = &sim->bodies[new_parent]; - body->local_position = vec3_sub(body->position, new_parent_body->position); - body->local_velocity = vec3_sub(body->velocity, new_parent_body->velocity); - } else { - // new_parent is root (Sun): global = local - body->local_position = body->position; - body->local_velocity = body->velocity; - } - } - ``` - -3. **Update `find_dominant_body()`** to properly handle -1 returns - -**Files to modify:** -- `src/simulation.cpp` (lines 103-121) -- `src/simulation.h` (no changes needed) - -**Estimated complexity:** Low -**Risk:** Medium (affects core transition logic) - -**Expected outcome:** -- ✅ Satellites can transition to/from Sun -- ✅ Enables Planet→Sun→Planet transfers -- ✅ Enables Star→Planet→Moon rendezvous - -**Tests to add:** -- Test satellite transitioning from Earth to Sun -- Test satellite transitioning from Sun to Mars -- Test full round-trip: Earth→Sun→Earth - ---- - -### Phase 2: Adaptive Hysteresis (Critical for Round-Trips) - -**Current Problem:** -The 0.5x hysteresis factor prevents oscillation but creates one-way barriers: -```cpp -if (distance < dist_to_current * 0.5) { - dominant = i; -} -``` - -**Decision:** Adaptive Hysteresis (Option B) - **DECIDED ✅** - -- Keep hysteresis but only apply when already in SOI -- Allow free switching when outside current SOI -- **Pros:** Prevents oscillation while enabling round-trips -- **Cons:** More complex logic - -**Option B Implementation:** -```cpp -if (can_switch && i != dominant) { - if (dominant == -1) { - dominant = i; - } else { - CelestialBody* current_parent = &sim->bodies[dominant]; - double dist_to_current = vec3_distance(body->position, current_parent->position); - - if (outside_current_soi) { - // Outside current SOI: switch to closest body (no hysteresis) - if (distance < dist_to_current) { - dominant = i; - } - } else { - // Inside current SOI: apply hysteresis to prevent oscillations - if (distance < dist_to_current * 0.5) { - dominant = i; - } - } - } -} -``` - -**Files to modify:** -- `src/simulation.cpp` (line 70-75) - -**Estimated complexity:** Low-Medium -**Risk:** Medium (may affect transition behavior) - -**Expected outcome:** -- ✅ Enables round-trip transitions (Earth→Sun→Earth) -- ✅ Maintains stability by preventing oscillation when inside SOI -- ✅ Allows free switching when outside current SOI - -**Tests to add:** -- Validate Satellite→Planet→Satellite round-trip -- Validate Earth→Sun→Mars→Sun→Earth full round-trip - ---- - -### Phase 3: Refactor Transition to Separate Function - -**Goal:** Cleaner code, easier to test, better separation of concerns - -**Current state:** Transition logic is inline in `update_simulation()` (lines 105-120) - -**Proposed refactoring:** - -**Add to `simulation.h`:** -```cpp -void transition_to_new_parent(SimulationState* sim, CelestialBody* body, - int old_parent_idx, int new_parent_idx); -``` - -**Add to `simulation.cpp`:** -```cpp -void transition_to_new_parent(SimulationState* sim, CelestialBody* body, - int old_parent_idx, int new_parent_idx) { - // Current state is in old parent's frame - Vec3 old_local_pos = body->local_position; - Vec3 old_local_vel = body->local_velocity; - - // Convert to global coordinates using old parent - if (old_parent_idx >= 0 && old_parent_idx < sim->body_count) { - CelestialBody* old_parent = &sim->bodies[old_parent_idx]; - body->position = vec3_add(old_local_pos, old_parent->position); - body->velocity = vec3_add(old_local_vel, old_parent->velocity); - } else { - // old_parent is root (Sun): local = global - body->position = old_local_pos; - body->velocity = old_local_vel; - } - - // Update parent index - body->parent_index = new_parent_idx; - - // Convert to local coordinates using new parent - if (new_parent_idx >= 0 && new_parent_idx < sim->body_count) { - CelestialBody* new_parent_body = &sim->bodies[new_parent_idx]; - body->local_position = vec3_sub(body->position, new_parent_body->position); - body->local_velocity = vec3_sub(body->velocity, new_parent_body->velocity); - } else { - // new_parent is root (Sun): global = local - body->local_position = body->position; - body->local_velocity = body->velocity; - } -} -``` - -**Update `update_simulation()`:** -```cpp -int new_parent = find_dominant_body(sim, i); -if (new_parent != body->parent_index) { - transition_to_new_parent(sim, body, body->parent_index, new_parent); -} -``` - -**Files to modify:** -- `src/simulation.h` (add function declaration) -- `src/simulation.cpp` (extract and refactor transition logic) - -**Estimated complexity:** Low -**Risk:** Low (pure refactor, no behavior change) - -**Expected outcome:** -- ✅ Cleaner code with better separation of concerns -- ✅ Easier to unit test transition logic -- ✅ Follows Phase 3 plan from hierarchical_frames_plan.md - -**Tests to add:** -- Unit tests for `transition_to_new_parent()` with all scenarios: - - Body→Body transition - - Body→Root transition - - Root→Body transition - - Root→Root transition (edge case) - ---- - -### Phase 4: Multi-Body Transition Test Configs - -**Goal:** Create realistic test scenarios for patched conics - -**Decision:** Create all three test cases first, expect failures for unimplemented features - **DECIDED ✅** - -**Implementation approach:** -1. Create all three test configurations -2. Run tests to establish baseline failures -3. Tests validate features as they're implemented -4. Comprehensive coverage from the start - -#### Test Config 1: Satellite Rendezvous -**File:** `tests/configs/satellite_rendezvous.toml` - -```toml -[[bodies]] -name = "Sun" -mass = 1.989e30 -radius = 6.96e8 -position = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = -1 -color = { r = 1.0, g = 1.0, b = 0.0 } -eccentricity = 0.0 -semi_major_axis = 0.0 - -[[bodies]] -name = "Earth" -mass = 5.972e24 -radius = 6.371e6 -position = { x = 1.496e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.0, g = 0.5, b = 1.0 } -eccentricity = 0.0 -semi_major_axis = 1.496e11 - -[[bodies]] -name = "Moon" -mass = 7.342e22 -radius = 1.737e6 -position = { x = 1.49984e11, y = 0.0, z = 0.0 } -parent_index = 1 -color = { r = 0.7, g = 0.7, b = 0.7 } -eccentricity = 0.0 -semi_major_axis = 3.844e8 - -[[bodies]] -name = "Satellite" -mass = 1.0e3 -radius = 1.0e1 -position = { x = 1.500e11, y = 1.0e8, z = 0.0 } -parent_index = 1 -color = { r = 1.0, g = 0.0, b = 1.0 } -eccentricity = 0.2 -semi_major_axis = 4.0e8 -``` - -**Scenario:** Satellite launches from Earth, transfers to Moon, returns - -#### Test Config 2: Interplanetary Transfer -**File:** `tests/configs/interplanetary_transfer.toml` - -```toml -[[bodies]] -name = "Sun" -mass = 1.989e30 -radius = 6.96e8 -position = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = -1 -color = { r = 1.0, g = 1.0, b = 0.0 } -eccentricity = 0.0 -semi_major_axis = 0.0 - -[[bodies]] -name = "Earth" -mass = 5.972e24 -radius = 6.371e6 -position = { x = 1.496e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.0, g = 0.5, b = 1.0 } -eccentricity = 0.0 -semi_major_axis = 1.496e11 - -[[bodies]] -name = "Mars" -mass = 6.39e23 -radius = 3.3895e6 -position = { x = 2.279e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.8, g = 0.3, b = 0.1 } -eccentricity = 0.0 -semi_major_axis = 2.279e11 - -[[bodies]] -name = "Probe" -mass = 1.0e3 -radius = 1.0e1 -position = { x = 1.496e11, y = 0.0, z = 0.0 } -parent_index = 1 -color = { r = 0.0, g = 1.0, b = 0.0 } -eccentricity = 0.5 -semi_major_axis = 1.888e11 -``` - -**Scenario:** Probe: Earth→Sun→Mars - -#### Test Config 3: Moon Capture -**File:** `tests/configs/moon_capture.toml` - -```toml -[[bodies]] -name = "Sun" -mass = 1.989e30 -radius = 6.96e8 -position = { x = 0.0, y = 0.0, z = 0.0 } -parent_index = -1 -color = { r = 1.0, g = 1.0, b = 0.0 } -eccentricity = 0.0 -semi_major_axis = 0.0 - -[[bodies]] -name = "Jupiter" -mass = 1.898e27 -radius = 6.9911e7 -position = { x = 7.785e11, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.9, g = 0.7, b = 0.5 } -eccentricity = 0.0 -semi_major_axis = 7.785e11 - -[[bodies]] -name = "Ganymede" -mass = 1.48e23 -radius = 2.634e6 -position = { x = 7.796e11, y = 0.0, z = 0.0 } -parent_index = 1 -color = { r = 0.6, g = 0.6, b = 0.5 } -eccentricity = 0.0 -semi_major_axis = 1.070e9 - -[[bodies]] -name = "Comet" -mass = 1.0e14 -radius = 5.0e3 -position = { x = 1.0e12, y = 0.0, z = 0.0 } -parent_index = 0 -color = { r = 0.5, g = 0.8, b = 1.0 } -eccentricity = 2.0 -semi_major_axis = -5.0e11 -``` - -**Scenario:** Comet: Sun→Jupiter→Ganymede→Sun - -**Files to create:** -- `tests/configs/satellite_rendezvous.toml` -- `tests/configs/interplanetary_transfer.toml` -- `tests/configs/moon_capture.toml` - -**Estimated complexity:** Low -**Risk:** Low (configs only, no code changes) - -**Expected outcome:** -- ✅ Realistic test scenarios for patched conics -- ✅ Covers multi-leg missions -- ✅ Tests root body transitions - ---- - -### Phase 5: Adaptive Timestepping (Performance + Accuracy) - -**Goal:** Different timesteps for different orbital phases - -**Decision:** DEFERRED to later work - **DECIDED ✅** - -**Problem:** Fixed 60s timestep is: -- Too coarse for fast orbital phases (moon capture) -- Too slow for deep-space phases - -**Proposed 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:** -1. Add per-body timesteps to `SimulationState` -2. Update `update_simulation()` to use adaptive timesteps -3. Add synchronization mechanism (multiple timesteps) - -**Complexity:** High -**Risk:** High (may affect energy conservation, requires careful testing) - -**Expected outcome:** -- ✅ Better accuracy for fast orbits (moon capture) -- ✅ Faster simulation for deep-space phases -- ✅ Energy conserved across transitions - -**Tests to add:** -- Verify energy drift with adaptive timesteps -- Verify orbital period accuracy with adaptive timesteps -- Test stability across SOI transitions - ---- - -### Phase 6: Enhanced Debugging & Visualization - -**Goal:** Better tools for debugging transitions and planning missions - -**Features to add:** - -#### 6.1 Transition Logging -```cpp -void log_transition(SimulationState* sim, CelestialBody* body, - int old_parent, int new_parent, double time) { - printf("[%.2f days] %s: parent %d → %d\n", - time / 86400.0, body->name, old_parent, new_parent); -} -``` - -#### 6.2 Visual SOI Boundaries -- Add wireframe spheres in renderer for SOI radii -- Toggle with keyboard key -- Use different colors for different bodies - -#### 6.3 Trajectory Prediction -- Predict future trajectory for given time span -- Show predicted SOI crossings -- Assist with mission planning - -**Files to modify:** -- `src/simulation.cpp` (logging) -- `src/renderer.cpp` (SOI visualization) -- `src/renderer.cpp` (trajectory prediction - new function) - -**Estimated complexity:** Medium -**Risk:** Low (mostly UI/visualization) - -**Expected outcome:** -- ✅ Better debugging tools for transitions -- ✅ Visual SOI boundaries -- ✅ Trajectory prediction for mission planning - ---- - -## Decisions Made - -### Decision 1: Hysteresis Strategy ✅ -**Chosen:** Option B - Adaptive hysteresis approach - -**Rationale:** -- Prevents oscillation while enabling round-trips -- Maintains stability during normal operation -- Allows free switching when outside current SOI -- Best balance between stability and flexibility - -**Implementation:** Will use adaptive hysteresis in Phase 2 (lines 70-75 in simulation.cpp) - ---- - -### Decision 2: Integration Timing ✅ -**Chosen:** Option A - Keep current approach (transition at start of timestep) - -**Rationale:** -- Simple, works for most cases -- Start with proven approach -- Defer optimization to future work - -**TODO:** Consider half-step transitions (Option B) if velocity discontinuities become problematic - ---- - -### Decision 3: Test Priorities ✅ -**Chosen:** Option C - Implement all three test cases first - -**Rationale:** -- Create all test configurations upfront -- Expect failures for unimplemented features -- Use tests as validation throughout implementation -- Comprehensive coverage from the start - -**Implementation:** -1. Create all three test configs (Phase 4) -2. Run tests to establish baseline failures -3. Implement features to make tests pass -4. Re-run tests after each phase - -**Test scenarios:** -- Satellite Rendezvous (Earth→Moon→Earth) -- Interplanetary Transfer (Earth→Sun→Mars) -- Moon Capture (Sun→Jupiter→Ganymede→Sun) - ---- - -### Decision 4: Adaptive Timesteps Priority ✅ -**Chosen:** Option B - Defer to later work - -**Rationale:** -- Focus on SOI transitions first -- Fixed 60s timestep works adequately for testing -- Optimize performance and accuracy after core features complete - -**TODO:** Implement adaptive timesteps in future update (Phase 5) -- Will address: Too coarse for fast orbits, too slow for deep space -- Estimated complexity: High -- Timeline: 2-3 days - ---- - -## Success Criteria - -### Phase 1 Success -- [ ] Satellite can transition to/from Sun -- [ ] Tests pass for Earth→Sun→Mars -- [ ] No energy conservation issues during transitions - -### Phase 2 Success -- [ ] Round-trip transitions work (Earth→Sun→Earth) -- [ ] No oscillation at SOI boundaries -- [ ] Tests validate stability - -### Phase 3 Success -- [ ] Transition logic extracted to separate function -- [ ] Unit tests cover all transition scenarios -- [ ] Code is cleaner and more maintainable - -### Phase 4 Success -- [ ] Three test configs created -- [ ] Baseline test failures documented -- [ ] Configs are realistic and well-documented - -### Phase 5 Success (Deferred) -- [ ] Adaptive timesteps implemented -- [ ] Energy drift < 1% with adaptive timesteps -- [ ] Performance improved for deep-space phases - -### Phase 6 Success (Optional) -- [ ] Transition logging works -- [ ] SOI boundaries visualized -- [ ] Trajectory prediction functional - ---- - -## Timeline Estimate - -- **Phase 1:** 1-2 days (fix root body transitions) -- **Phase 2:** 1 day (adaptive hysteresis - decision made ✅) -- **Phase 3:** 0.5 days (refactoring) -- **Phase 4:** 1 day (test configs - create all three first) -- **Phase 5:** 2-3 days (adaptive timesteps - DEFERRED ⏸️) -- **Phase 6:** 1-2 days (debugging/visualization - optional) - -**Total for core features (Phases 1-4):** 4-5 days -**Total with all features:** 8-10 days (including deferred Phases 5-6) - -**Implementation approach:** -1. Create all three test configs (Phase 4) -2. Implement core transition features (Phases 1-3) -3. Validate with tests after each phase -4. Defer Phases 5-6 to future work - ---- - -## Dependencies - -### Required -- ✅ Hierarchical coordinate frames (complete) -- ✅ Local frame integration (complete) -- ✅ Parent-first update order (complete) -- ⏸️ Root body transitions (Phase 1 - pending) - -### Optional -- ⏸️ Adaptive timesteps (Phase 5 - optional) -- ⏸️ Debugging tools (Phase 6 - optional) - ---- - -## Risks and Mitigations - -### High Risk -- **Energy conservation during transitions** - - Mitigation: Careful testing, energy drift checks - - Backup: Keep old code for rollback - -- **Numerical precision across scales** - - Mitigation: Use local frames (already implemented) - - Backup: Double precision (already used) - -### Medium Risk -- **Oscillation at SOI boundaries** - - Mitigation: Adaptive hysteresis (Phase 2) - - Backup: Increase hysteresis factor if needed - -- **Timestep too coarse for fast orbits** - - Mitigation: Adaptive timesteps (Phase 5 - optional) - - Backup: Reduce fixed timestep if needed - -### Low Risk -- **Code complexity increases** - - Mitigation: Good unit tests, refactoring (Phase 3) - - Backup: Keep functions small and focused - ---- - -## References - -- `docs/hierarchical_frames_plan.md` - Phase 3: SOI Transition with Frame Transform -- `docs/implementation_plan.md` - SOI Transition Mechanics section -- `src/simulation.cpp` - Current SOI transition implementation (lines 103-121) -- `tests/test_soi_transition.cpp` - Current SOI transition tests