14 KiB
Hierarchical Coordinate Frames Implementation Plan
Status: Phase 2 Complete ✅
Last Updated: 2026-01-09
Current Progress:
- ✅ Phase 1: Foundation (Dual coordinate storage)
- ✅ Phase 2: Local frame integration (Earth Moon test passing!)
- ⏸️ Phase 3: SOI transitions with frame transforms (deferred)
- ⏸️ Phase 4: Parent-first update order (deferred)
- ⏸️ Phase 5: Validation & optimization (deferred)
Test Results After Phase 2:
- Tests passing: 7/9 (78%)
- Moon orbital stability around Earth: ✅ PASSING (was failing)
- Io orbital stability: ❌ Still failing (orbit not completing)
- Titan orbital stability: ❌ Still failing (NaN drift)
Commits:
92be7f8- Phase 1: Add local coordinate frame storage (no behavior change)052efff- Phase 2: Local frame integration (Earth Moon test now passing!)
Goal
Transform the simulation from global coordinate space to hierarchical local frames to:
- Improve numerical precision for moon orbits
- Isolate planetary perturbations from affecting moons
- Enable future patched conics implementation for satellites
- Support SOI transitions with proper coordinate transformations
Current System Analysis
Storage (Global Coordinates):
CelestialBody.position- absolute position in Sun-centered frameCelestialBody.velocity- absolute velocity in Sun-centered frameCelestialBody.parent_index- determines which body to calculate gravity from
Physics Integration:
evaluate_acceleration()- calculates gravity force from parent only (2-body approximation)rk4_step()- integrates using global coordinates- SOI transitions change
parent_index, but coordinates stay in global frame
Key Observation:
Line 145 in simulation.cpp already composes velocities: body->velocity = vec3_add(body->velocity, parent->velocity)
This indicates the system is already partially thinking in local frames during initialization, but integrates in global frame.
Proposed Architecture: "Local Frame Integration"
Data Structure: Dual Storage (Recommended)
Store both local and global coordinates:
struct CelestialBody {
char name[64];
double mass;
double radius;
// NEW: Local coordinates (relative to parent)
Vec3 local_position; // position relative to parent
Vec3 local_velocity; // velocity relative to parent
// Keep for rendering/backward compatibility
Vec3 position; // global position (computed from local)
Vec3 velocity; // global velocity (computed from local)
double soi_radius;
int parent_index;
float color[3];
double eccentricity;
double semi_major_axis;
};
Advantages:
- Easy rendering (global positions readily available)
- Easy SOI checks (global positions)
- Clear separation of concerns
- Memory negligible for ~14 bodies (48 bytes per body)
Physics Integration Flow
Current:
body (global) → RK4 in global coords → body (global)
Proposed:
body (local) → RK4 in local coords → body (local) → compute global
Update Order: Parent-First (Recommended)
void update_simulation(SimulationState* sim) {
// 1. Update all root bodies (in their own frame = global)
for (int i = 0; i < sim->body_count; i++) {
if (sim->bodies[i].parent_index == -1) {
rk4_step_local(&sim->bodies[i], ctx, sim->dt);
}
}
// 2. Compute global positions for roots
compute_global_coordinates_for_roots(sim);
// 3. Update all child bodies (in parent's frame)
for (int i = 0; i < sim->body_count; i++) {
CelestialBody* body = &sim->bodies[i];
if (body->parent_index >= 0) {
// Check for SOI transition
int new_parent = find_dominant_body(sim, i);
if (new_parent != body->parent_index && new_parent != -1) {
transition_to_new_parent(body, body->parent_index,
new_parent, sim);
}
// Integrate in local frame
rk4_step_local(body, ctx, sim->dt);
}
}
// 4. Compute global positions for all children
compute_global_coordinates_for_children(sim);
sim->time += sim->dt;
}
SOI Transition with Frame Transform
Critical piece for satellites and patched conics:
void transition_to_new_parent(CelestialBody* body, int old_parent_idx,
int new_parent_idx, SimulationState* sim) {
// Current state is in old parent's frame
Vec3 old_local_pos = body->local_position;
Vec3 old_local_vel = body->local_velocity;
// Get old and new parent
CelestialBody* old_parent = (old_parent_idx >= 0)
? &sim->bodies[old_parent_idx] : NULL;
CelestialBody* new_parent = &sim->bodies[new_parent_idx];
// Compute global position (or use cached global coords)
Vec3 global_pos = old_parent ? vec3_add(old_local_pos, old_parent->position)
: old_local_pos;
Vec3 global_vel = old_parent ? vec3_add(old_local_vel, old_parent->velocity)
: old_local_vel;
// Transform to new parent's frame
body->local_position = vec3_sub(global_pos, new_parent->position);
body->local_velocity = vec3_sub(global_vel, new_parent->velocity);
body->parent_index = new_parent_idx;
}
Implementation Phases
Phase 1: Foundation (No Behavior Change)
Goal: Add local coordinate storage without changing physics
Tasks:
- Add
local_positionandlocal_velocitytoCelestialBody - Add
initialize_local_coordinates()- convert global→local on load - Add
compute_global_coordinates()- convert local→global after update - Modify
update_simulation()to call both functions - Verify: All tests still pass (same behavior)
Files to modify:
src/simulation.h(add fields)src/simulation.cpp(add conversion functions)src/config_loader.cpp(call initialize_local_coordinates)
Estimated complexity: Low Risk: Very low (pure refactor, no logic change)
Expected outcome:
- ✅ Dual coordinate storage in place
- ✅ No behavior change (all tests same status)
- ✅ Foundation for local frame integration
Status: COMPLETE ✅
- Commit:
92be7f8 - Date: 2026-01-09
- Test status: 6/9 passing (3 moon failures, unchanged from baseline)
Phase 2: Local Frame Integration
Goal: Actually integrate in local frames
Tasks:
- Create
rk4_step_local()- integrates using local coordinates - Modify
evaluate_acceleration()to work in local frame (parent at origin) - Update
update_simulation()to use local frame integration - Verify: Moon tests improve (should see reduced drift)
Files to modify:
src/physics.cpp(modify rk4_step, evaluate_acceleration)src/simulation.cpp(update call sites)
Estimated complexity: Medium Risk: Medium (core physics change)
Expected outcome:
- ✅ Moon drift issues should be fixed (improved numerical precision)
- ✅ Test failures reduced (Moon, Io, Titan tests should pass)
- ✅ Physics happens in local frames
Status: COMPLETE ✅
- Commit:
052efff - Date: 2026-01-09
- Test status: 7/9 passing (major improvement!)
- ✅ Earth Moon test: NOW PASSING (was failing with 20% drift)
- ❌ Io test: Still failing (orbit not completing in time limit)
- ❌ Titan test: Still failing (NaN drift, numerical issue)
Implementation Details:
- Modified
rk4_step()to integratelocal_positionandlocal_velocity - Modified
evaluate_acceleration()to calculate gravity with parent at origin - For child bodies in local frame:
distance = magnitude(position),direction = -normalize(position) update_simulation()now callscompute_global_coordinates()after integration- Root bodies updated first, then global coords computed, then child bodies updated
Key Insight - Why It Works: The local frame integration provides improved numerical precision by:
- Eliminating large offsets (Moon integrates at ~3.8×10⁸ m instead of ~1.5×10¹¹ m)
- Isolating moon orbits from planetary perturbations on parent
- Maintaining full floating-point precision for small orbital changes
Remaining Issues:
- Io and Titan failures suggest timestep may be too coarse for distant/fast moons
- Or additional numerical stability improvements needed
- Not critical - major goal achieved (Earth Moon stable)
Phase 3: SOI Transition with Frame Transform
Status: Not yet implemented (deferred) Goal: Properly handle coordinate transformations during SOI crossings
Tasks:
- Create
transition_to_new_parent()function - Modify SOI transition logic in
update_simulation() - Add tests for comet SOI transitions (Sun→Mars→Sun)
- Verify: Comet test still passes with smooth transitions
Files to modify:
src/simulation.cpp(SOI transition logic)tests/test_comet_orbit.cpp(verify transitions)
Estimated complexity: Medium Risk: Medium (affects patched conics later)
Expected outcome:
- ✅ SOI transitions properly transform coordinates
- ✅ Foundation for patched conics implementation
- ✅ Comet transitions validated
Status: Not yet implemented (deferred)
Note: Currently SOI transitions just change parent_index. In local frame integration,
this may cause position/velocity discontinuities. Phase 3 will implement proper coordinate
transformations during transitions: new_local = global - new_parent_global.
Phase 4: Parent-First Update Order
Goal: Update hierarchy in correct order
Status: Partially implemented
Tasks:
- Refactor
update_simulation()to update roots first, then children - Ensure parent global positions are current before children update
- Verify: No regression in tests
Files to modify:
src/simulation.cpp(update_simulation)
Estimated complexity: Low-Medium Risk: Low
Expected outcome:
- ✅ Hierarchical update order implemented
- ✅ Parent positions current when updating children
Status: Partially implemented
Current Implementation:
- Root bodies are updated first
compute_global_coordinates()called after root update- Then child bodies updated (using updated parent global positions)
compute_global_coordinates()called again after child update
This is effectively parent-first order! Root bodies complete integration before children start, and children use current parent positions. However, children still use parent positions from START of timestep during their RK4 integration.
Future Refinement (if needed): Could pass updated parent position into child RK4 steps for even higher accuracy. Current approach is semi-implicit and works well for Phase 2 results.
Phase 5: Validation & Optimization
Status: Not yet implemented (deferred) Goal: Ensure correctness and performance
Tasks:
- Add test for frame transformations
- Profile performance (should be similar or better)
- Add documentation comments explaining coordinate systems
- Update implementation_plan.md
Files to modify:
tests/(new frame transform tests)docs/implementation_plan.md
Expected outcome:
- ✅ Fully validated hierarchical coordinate system
- ✅ Documentation complete
- ✅ Ready for satellite/spacecraft simulation
Status: Not yet implemented (deferred)
Summary of Current State
What Works:
- ✅ Dual coordinate storage (local + global)
- ✅ Local frame integration for all bodies
- ✅ Automatic global coordinate computation
- ✅ Earth-Moon orbital stability (major success!)
- ✅ Improved numerical precision for nested orbits
- ✅ Clean separation of local/global coordinate systems
What's Deferred:
- ⏸️ SOI transition frame transformations (Phase 3)
- ⏸️ Full validation suite (Phase 5)
- ⏸️ Io and Titan orbital tuning
Ready For:
- Continued development of patched conics (after Phase 3)
- Satellite/spacecraft simulation (will need Phase 3 for SOI crossing)
- Further orbital mechanics improvements
Notes for Future Development:
- Phase 3 (SOI transitions) is critical for spacecraft that cross SOI boundaries
- Current SOI transitions work but don't transform coordinates properly
- May need adaptive timesteps or smaller fixed timesteps for outer moons (Io, Titan)
- Consider adding orbit tracker diagnostics to debug remaining failures
Design Decisions
Config Format
Keep global positions in config (backward compatible). Convert to local coordinates on load via initialize_local_coordinates().
Storage Strategy
Dual storage (both local and global) for performance and simplicity.
Multi-level Hierarchies
Not implementing at this time. Maximum 2 levels: Sun→Planet→Moon. Design allows future extension to Sun→Planet→Moon→Satellite if needed.
Timestep Strategy
Single global timestep for entire simulation during initial implementation. Per-level timesteps deferred for future optimization.
Risk Assessment
Low Risk:
- Phase 1 (pure refactor, no logic change)
- Phase 4 (update order change)
Medium Risk:
- Phase 2 (core physics change - but testable)
- Phase 3 (frame transforms - complex but well-defined)
Mitigation:
- Implement phases incrementally with manual review after each phase
- Keep old code commented for comparison
- Add validation tests at each phase
- Can roll back if tests regress
Expected Final Outcomes
After all phases complete:
- ✅ Moon orbital stability vastly improved (test failures fixed)
- ✅ Numerical precision improved for nested orbits
- ✅ SOI transitions with proper coordinate frame transformations
- ✅ Foundation for patched conics and satellite simulation
- ✅ Parent-first hierarchical update order
- ✅ Fully documented coordinate system architecture