Browse Source

Remove headless mode and legacy test documentation: simplify main.cpp, update README with Testing section, delete obsolete test_verification.md, remove test-manual target from Makefile

main
cinnaboot 6 months ago
parent
commit
1c59da8c41
  1. 5
      Makefile
  2. 15
      README.md
  3. 61
      docs/test_verification.md
  4. 160
      src/main.cpp

5
Makefile

@ -68,9 +68,6 @@ rebuild: clean all
run: $(TARGET)
./$(TARGET)
# Run manual integration test with simulation
test-manual: $(TARGET)
./$(TARGET) configs/test_simple.toml --headless --readable --days 365
# Build automated test suite
test-build:
@ -101,4 +98,4 @@ test-build:
test: test-build
./$(TEST_TARGET)
.PHONY: all clean clean-all rebuild run test test-build test-manual raylib
.PHONY: all clean clean-all rebuild run test test-build raylib

15
README.md

@ -56,9 +56,22 @@ make clean-all # Clean everything including raylib
- **[Technical Reference](docs/implementation_plan.md)** - Data structures and module overview
- **[Detailed Architecture](docs/verbose_project_overview.md)** - Complete implementation details and data flow
- **[Testing Guide](docs/test_verification.md)** - Verification commands and expected behavior
- **[Known Issues](docs/config_assumptions.md)** - Configuration bugs and future improvements
## Testing
```bash
make test # Run full automated test suite
```
The test suite validates:
- Orbital period accuracy (Earth, Mars)
- Energy conservation (RK4 integration)
- SOI transitions and multi-body interactions
- Eccentric orbit behavior (comets, parabolic, hyperbolic)
All tests use Catch2 framework with configurable time steps and durations.
## License
This project is provided as-is for educational and research purposes.

61
docs/test_verification.md

@ -1,61 +0,0 @@
# Test Verification Guide
Quick reference for testing orbital mechanics using `configs/test_simple.txt`.
## Test Command
```bash
make
./orbit_sim configs/test_simple.txt --headless --readable --days 365
```
## Test Bodies
- **Sun**: Origin (0, 0, 0)
- **Earth**: 1.0 AU, circular orbit (e=0), period ~365 days
- **Mars**: 1.5 AU, circular orbit (e=0), period ~687 days
- **Comet**: 2.5 AU semi-major axis, eccentric orbit (e=0.7), period ~1444 days
- Starts at perihelion (0.75 AU)
- Aphelion at 4.25 AU
All orbit counter-clockwise (viewed from +Z).
## Expected Behavior
**Circular orbits (Earth, Mars):**
- Distance from Sun remains constant
- Velocity magnitude remains constant
- Earth: ~29.8 km/s
- Mars: ~24.3 km/s
- Return to starting position after full period
**Eccentric orbit (Comet):**
- Distance varies: 0.75 AU (perihelion) to 4.25 AU (aphelion)
- Velocity varies: faster at perihelion, slower at aphelion
- Period ~1444 days
## Quick Tests
```bash
# Earth full orbit
./orbit_sim configs/test_simple.txt --headless --readable --days 365
# Mars full orbit
./orbit_sim configs/test_simple.txt --headless --readable --days 687
# Comet full orbit (eccentric)
./orbit_sim configs/test_simple.txt --headless --readable --days 1444
```
## Acceptable Tolerances
Due to Euler integration with dt=60s:
- Distance variation: ±0.001 AU
- Velocity variation: ±0.1 km/s
- Position after full orbit: Within 0.01 AU of start
## Output Flags
- `--headless`: Terminal output only (no GUI)
- `--readable`: Human-friendly units (AU, km/s) instead of SI (m, m/s)
- `--days N`: Simulation duration in days

160
src/main.cpp

@ -9,64 +9,16 @@
// Configuration defaults - edit to change default run mode
#define DEFAULT_CONFIG_FILE "configs/test_simple.toml"
#define DEFAULT_HEADLESS 0 // 0 = GUI mode, 1 = headless mode
#define DEFAULT_READABLE 1 // 0 = scientific notation, 1 = human-readable (AU, km/s)
#define DEFAULT_SIM_DAYS 365 // Default simulation duration for headless mode
// Unit conversion constants
const double AU = 1.496e11; // 1 AU in meters
const double KM = 1000.0; // 1 km in meters
// Helper functions for human-readable output
void print_position_readable(const char* name, Vec3 pos) {
double dist_au = vec3_magnitude(pos) / AU;
double x_au = pos.x / AU;
double y_au = pos.y / AU;
double z_au = pos.z / AU;
// Calculate polar coordinates (angle in XY plane)
double angle_rad = atan2(pos.y, pos.x);
double angle_deg = angle_rad * 180.0 / M_PI;
if (angle_deg < 0.0) angle_deg += 360.0; // Convert to 0-360 range
printf("%s:\n", name);
printf(" Position: (%.6f, %.6f, %.6f) AU\n", x_au, y_au, z_au);
printf(" Polar (XY plane): r=%.6f AU, θ=%.2f°\n", dist_au, angle_deg);
}
void print_velocity_readable(const char* name, Vec3 vel) {
double speed_km_s = vec3_magnitude(vel) / KM;
printf(" Velocity magnitude: %.3f km/s\n", speed_km_s);
printf(" Velocity: (%.3f, %.3f, %.3f) km/s\n",
vel.x / KM, vel.y / KM, vel.z / KM);
}
void print_body_readable(CelestialBody* body) {
print_position_readable(body->name, body->position);
print_velocity_readable(body->name, body->velocity);
}
struct ProgramArgs {
const char* config_file;
bool headless;
bool readable;
int sim_duration_days;
};
void parse_command_line_args(int argc, char** argv, ProgramArgs* args) {
args->config_file = DEFAULT_CONFIG_FILE;
args->headless = DEFAULT_HEADLESS;
args->readable = DEFAULT_READABLE;
args->sim_duration_days = DEFAULT_SIM_DAYS;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--headless") == 0 || strcmp(argv[i], "-h") == 0) {
args->headless = true;
} else if (strcmp(argv[i], "--readable") == 0 || strcmp(argv[i], "-r") == 0) {
args->readable = true;
} else if (strcmp(argv[i], "--days") == 0 && i + 1 < argc) {
args->sim_duration_days = atoi(argv[++i]);
} else if (argv[i][0] != '-') {
if (argv[i][0] != '-') {
args->config_file = argv[i];
}
}
@ -75,110 +27,6 @@ void parse_command_line_args(int argc, char** argv, ProgramArgs* args) {
void print_startup_info(const ProgramArgs* args) {
printf("=== Orbital Mechanics Simulation ===\n");
printf("Loading configuration: %s\n", args->config_file);
if (args->headless) {
printf("Mode: Headless (terminal output only)\n");
printf("Duration: %d days\n", args->sim_duration_days);
if (args->readable) {
printf("Output: Human-readable units (AU, km/s)\n");
}
}
}
void run_headless_simulation(SimulationState* sim, const ProgramArgs* args) {
const double SECONDS_PER_DAY = 86400.0;
const double total_time = args->sim_duration_days * SECONDS_PER_DAY;
const double output_interval = SECONDS_PER_DAY;
double next_output_time = 0.0;
CelestialBody* initial_state = (CelestialBody*)malloc(sim->body_count * sizeof(CelestialBody));
int* previous_parents = (int*)malloc(sim->body_count * sizeof(int));
for (int i = 0; i < sim->body_count; i++) {
initial_state[i] = sim->bodies[i];
previous_parents[i] = sim->bodies[i].parent_index;
}
printf("\n=== Initial State ===\n");
for (int i = 0; i < sim->body_count; i++) {
CelestialBody* body = &sim->bodies[i];
if (args->readable) {
print_body_readable(body);
} else {
printf("%s:\n", body->name);
printf(" Position: (%.3e, %.3e, %.3e) m\n",
body->position.x, body->position.y, body->position.z);
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n",
body->velocity.x, body->velocity.y, body->velocity.z);
}
}
printf("\n=== Running Simulation ===\n");
while (sim->time < total_time) {
update_simulation(sim);
for (int i = 0; i < sim->body_count; i++) {
int current_parent = sim->bodies[i].parent_index;
if (current_parent != previous_parents[i]) {
printf("\n*** PARENT CHANGE at Day %.1f ***\n", sim->time / SECONDS_PER_DAY);
printf(" Body: %s\n", sim->bodies[i].name);
printf(" Old parent: %d", previous_parents[i]);
if (previous_parents[i] >= 0) printf(" (%s)", sim->bodies[previous_parents[i]].name);
printf("\n");
printf(" New parent: %d", current_parent);
if (current_parent >= 0) printf(" (%s)", sim->bodies[current_parent].name);
printf("\n\n");
previous_parents[i] = current_parent;
}
}
if (sim->time >= next_output_time) {
printf("Day %.1f: ", sim->time / SECONDS_PER_DAY);
for (int i = 0; i < sim->body_count && i < 3; i++) {
Vec3 pos = sim->bodies[i].position;
double dist = vec3_magnitude(pos);
if (args->readable) {
double angle_rad = atan2(pos.y, pos.x);
double angle_deg = angle_rad * 180.0 / M_PI;
if (angle_deg < 0.0) angle_deg += 360.0;
printf("%s(r=%.4f AU, θ=%.1f°) ", sim->bodies[i].name, dist / AU, angle_deg);
} else {
printf("%s=%.3e m ", sim->bodies[i].name, dist);
}
}
printf("\n");
next_output_time += output_interval;
}
}
printf("\n=== Initial State (Day 0.0) ===\n");
for (int i = 0; i < sim->body_count; i++) {
CelestialBody* body = &initial_state[i];
if (args->readable) {
print_body_readable(body);
} else {
printf("%s:\n", body->name);
printf(" Position: (%.3e, %.3e, %.3e) m\n",
body->position.x, body->position.y, body->position.z);
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n",
body->velocity.x, body->velocity.y, body->velocity.z);
}
}
printf("\n=== Final State (Day %.1f) ===\n", sim->time / SECONDS_PER_DAY);
for (int i = 0; i < sim->body_count; i++) {
CelestialBody* body = &sim->bodies[i];
if (args->readable) {
print_body_readable(body);
} else {
printf("%s:\n", body->name);
printf(" Position: (%.3e, %.3e, %.3e) m\n",
body->position.x, body->position.y, body->position.z);
printf(" Velocity: (%.3e, %.3e, %.3e) m/s\n",
body->velocity.x, body->velocity.y, body->velocity.z);
}
}
free(initial_state);
free(previous_parents);
}
void run_gui_simulation(SimulationState* sim) {
@ -249,11 +97,7 @@ int main(int argc, char** argv) {
return 1;
}
if (args.headless) {
run_headless_simulation(sim, &args);
} else {
run_gui_simulation(sim);
}
run_gui_simulation(sim);
destroy_simulation(sim);
return 0;

Loading…
Cancel
Save