vibe coding an orbital mechanics simulation to try out claude code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

149 lines
5.5 KiB

#include <catch2/catch_test_macros.hpp>
#include "../src/physics.h"
#include "../src/mission_planning.h"
#include "../src/simulation.h"
#include "../src/config_loader.h"
#include <cmath>
const double AU = 1.496e11;
const double M_SUN = 1.989e30;
const double M_EARTH = 5.972e24;
const double M_MARS = 6.39e23;
const double R_EARTH = 1.496e11;
const double R_MARS = 2.279e11;
const double SECONDS_PER_DAY = 86400.0;
TEST_CASE("Hohmann transfer - Earth to Mars", "[mission][hohmann]") {
TransferParameters params = calculate_hohmann_transfer(R_EARTH, R_MARS, M_SUN);
INFO("Semi-major axis: " << params.semi_major_axis / AU << " AU");
INFO("Eccentricity: " << params.eccentricity);
INFO("Transfer time: " << params.transfer_time / SECONDS_PER_DAY << " days");
INFO("Departure velocity: " << params.departure_velocity / 1000.0 << " km/s");
INFO("Arrival velocity: " << params.arrival_velocity / 1000.0 << " km/s");
INFO("Phase angle: " << params.phase_angle_deg << " degrees");
INFO("Delta-v injection: " << params.delta_v_injection / 1000.0 << " km/s");
double expected_transfer_time = 259.0 * SECONDS_PER_DAY;
double transfer_time_error = fabs(params.transfer_time - expected_transfer_time) / expected_transfer_time;
REQUIRE(transfer_time_error < 0.05);
double expected_phase_angle = 44.3;
double phase_angle_error = fabs(params.phase_angle_deg - expected_phase_angle);
REQUIRE(phase_angle_error < 1.0);
double expected_delta_v = 2940.0;
double delta_v_error = fabs(params.delta_v_injection - expected_delta_v) / expected_delta_v;
REQUIRE(delta_v_error < 0.05);
}
TEST_CASE("Hohmann transfer - Mars to Earth", "[mission][hohmann][reverse]") {
TransferParameters params = calculate_hohmann_transfer(R_MARS, R_EARTH, M_SUN);
INFO("Transfer time (return): " << params.transfer_time / SECONDS_PER_DAY << " days");
INFO("Phase angle (return): " << params.phase_angle_deg << " degrees");
INFO("Delta-v injection (return): " << params.delta_v_injection / 1000.0 << " km/s");
REQUIRE(params.transfer_time > 0);
double expected_sma = (R_EARTH + R_MARS) / 2.0;
double sma_error = fabs(params.semi_major_axis - expected_sma) / expected_sma;
REQUIRE(sma_error < 0.01);
}
TEST_CASE("Angular position - circular orbit", "[mission][angular]") {
SimulationState* sim = create_simulation(10, 60.0);
REQUIRE(load_system_config(sim, "tests/configs/earth_circular.toml"));
CelestialBody* earth = &sim->bodies[1];
CelestialBody* sun = &sim->bodies[0];
double angle = calculate_angular_position(earth, sun);
INFO("Earth angular position: " << angle << " rad (" << angle * 180.0 / M_PI << " deg)");
REQUIRE(angle >= 0.0);
REQUIRE(angle < 2.0 * M_PI);
update_simulation(sim);
double angle_after = calculate_angular_position(earth, sun);
INFO("Earth angular position after update: " << angle_after << " rad ("
<< angle_after * 180.0 / M_PI << " deg)");
REQUIRE(angle_after >= 0.0);
REQUIRE(angle_after < 2.0 * M_PI);
destroy_simulation(sim);
}
TEST_CASE("Phase angle calculation", "[mission][phase]") {
double earth_period = 365.25 * SECONDS_PER_DAY;
double mars_period = 687.0 * SECONDS_PER_DAY;
double transfer_time = 259.0 * SECONDS_PER_DAY;
double phase_angle = calculate_required_phase_angle(transfer_time, mars_period);
INFO("Required phase angle: " << phase_angle << " degrees");
REQUIRE(phase_angle >= 0.0);
REQUIRE(phase_angle < 360.0);
double expected_phase_angle = 44.3;
double phase_error = fabs(phase_angle - expected_phase_angle);
REQUIRE(phase_error < 1.0);
}
TEST_CASE("Launch window detection", "[mission][window]") {
const double TIME_STEP = 60.0;
SimulationState* sim = create_simulation(10, TIME_STEP);
REQUIRE(load_system_config(sim, "tests/configs/earth_mars_simple.toml"));
const int EARTH_IDX = 1;
const int MARS_IDX = 2;
double r_earth = vec3_distance(sim->bodies[EARTH_IDX].position, sim->bodies[0].position);
double r_mars = vec3_distance(sim->bodies[MARS_IDX].position, sim->bodies[0].position);
TransferParameters params = calculate_hohmann_transfer(r_earth, r_mars, sim->bodies[0].mass);
bool window_open = check_launch_window(sim, EARTH_IDX, MARS_IDX,
params.phase_angle_deg, 5.0);
INFO("Phase angle required: " << params.phase_angle_deg << " degrees");
INFO("Launch window open: " << (window_open ? "YES" : "NO"));
REQUIRE(!window_open);
destroy_simulation(sim);
}
TEST_CASE("Wait for launch window", "[mission][wait]") {
const double TIME_STEP = 60.0;
SimulationState* sim = create_simulation(10, TIME_STEP);
REQUIRE(load_system_config(sim, "tests/configs/earth_mars_simple.toml"));
const int EARTH_IDX = 1;
const int MARS_IDX = 2;
double r_earth = vec3_distance(sim->bodies[EARTH_IDX].position, sim->bodies[0].position);
double r_mars = vec3_distance(sim->bodies[MARS_IDX].position, sim->bodies[0].position);
TransferParameters params = calculate_hohmann_transfer(r_earth, r_mars, sim->bodies[0].mass);
double start_time = sim->time;
wait_for_launch_window(sim, EARTH_IDX, MARS_IDX, params.phase_angle_deg, 1.0);
double end_time = sim->time;
double wait_time = (end_time - start_time) / SECONDS_PER_DAY;
INFO("Waited " << wait_time << " days for launch window");
bool window_open = check_launch_window(sim, EARTH_IDX, MARS_IDX,
params.phase_angle_deg, 1.0);
REQUIRE(window_open);
destroy_simulation(sim);
}