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.
214 lines
7.2 KiB
214 lines
7.2 KiB
#include <catch2/catch_test_macros.hpp> |
|
#include "../src/physics.h" |
|
#include "../src/orbital_mechanics.h" |
|
#include "../src/simulation.h" |
|
#include "../src/config_loader.h" |
|
#include <cmath> |
|
|
|
const double VELOCITY_TOLERANCE = 1.0e-6; |
|
const double POSITION_TOLERANCE = 1.0e3; |
|
|
|
TEST_CASE("Highly eccentric orbit (e=0.99)", "[extreme][eccentricity][high]") { |
|
const double TIME_STEP = 60.0; |
|
|
|
SimulationState* sim = create_simulation(10, 3, 0, TIME_STEP); |
|
|
|
REQUIRE(load_system_config(sim, "tests/test_extreme_eccentricity.toml")); |
|
|
|
Spacecraft* high_e = &sim->spacecraft[0]; |
|
CelestialBody* earth = &sim->bodies[0]; |
|
|
|
INFO("Testing spacecraft with e=" << high_e->orbit.eccentricity); |
|
|
|
Vec3 pos; |
|
Vec3 vel; |
|
orbital_elements_to_cartesian(high_e->orbit, earth->mass, &pos, &vel); |
|
|
|
double r = vec3_magnitude(pos); |
|
double v = vec3_magnitude(vel); |
|
|
|
double expected_r_perigee = high_e->orbit.semi_major_axis * (1.0 - high_e->orbit.eccentricity); |
|
double expected_r_apogee = high_e->orbit.semi_major_axis * (1.0 + high_e->orbit.eccentricity); |
|
|
|
INFO("Semi-major axis: " << high_e->orbit.semi_major_axis << " m"); |
|
INFO("Eccentricity: " << high_e->orbit.eccentricity); |
|
INFO("Radius: " << r << " m"); |
|
INFO("Velocity: " << v << " m/s"); |
|
INFO("Expected perigee: " << expected_r_perigee << " m"); |
|
INFO("Expected apogee: " << expected_r_apogee << " m"); |
|
|
|
REQUIRE(r >= expected_r_perigee * 0.9); |
|
REQUIRE(r <= expected_r_apogee * 1.1); |
|
REQUIRE(v > 0.0); |
|
|
|
destroy_simulation(sim); |
|
} |
|
|
|
TEST_CASE("Near-parabolic orbit (e=0.9999)", "[extreme][eccentricity][near_parabolic]") { |
|
const double TIME_STEP = 60.0; |
|
|
|
SimulationState* sim = create_simulation(10, 3, 0, TIME_STEP); |
|
|
|
REQUIRE(load_system_config(sim, "tests/test_extreme_eccentricity.toml")); |
|
|
|
Spacecraft* near_parabolic = &sim->spacecraft[1]; |
|
CelestialBody* earth = &sim->bodies[0]; |
|
|
|
INFO("Testing spacecraft with e=" << near_parabolic->orbit.eccentricity); |
|
|
|
Vec3 pos_perigee; |
|
Vec3 vel_perigee; |
|
near_parabolic->orbit.true_anomaly = 0.0; |
|
orbital_elements_to_cartesian(near_parabolic->orbit, earth->mass, &pos_perigee, &vel_perigee); |
|
|
|
double r_perigee = vec3_magnitude(pos_perigee); |
|
double v_perigee = vec3_magnitude(vel_perigee); |
|
|
|
Vec3 pos_apogee; |
|
Vec3 vel_apogee; |
|
near_parabolic->orbit.true_anomaly = M_PI; |
|
orbital_elements_to_cartesian(near_parabolic->orbit, earth->mass, &pos_apogee, &vel_apogee); |
|
|
|
double r_apogee = vec3_magnitude(pos_apogee); |
|
double v_apogee = vec3_magnitude(vel_apogee); |
|
|
|
double expected_r_perigee = near_parabolic->orbit.semi_major_axis * (1.0 - near_parabolic->orbit.eccentricity); |
|
double expected_r_apogee = near_parabolic->orbit.semi_major_axis * (1.0 + near_parabolic->orbit.eccentricity); |
|
|
|
INFO("Perigee:"); |
|
INFO(" Radius: " << r_perigee << " m (expected: " << expected_r_perigee << " m)"); |
|
INFO(" Velocity: " << v_perigee << " m/s"); |
|
|
|
INFO("Apogee:"); |
|
INFO(" Radius: " << r_apogee << " m (expected: " << expected_r_apogee << " m)"); |
|
INFO(" Velocity: " << v_apogee << " m/s"); |
|
|
|
double r_perigee_error = fabs(r_perigee - expected_r_perigee); |
|
double r_apogee_error = fabs(r_apogee - expected_r_apogee); |
|
|
|
REQUIRE(r_perigee_error < POSITION_TOLERANCE); |
|
REQUIRE(r_apogee_error < POSITION_TOLERANCE); |
|
REQUIRE(v_perigee > v_apogee); |
|
REQUIRE(r_apogee > r_perigee); |
|
|
|
destroy_simulation(sim); |
|
} |
|
|
|
TEST_CASE("Near-parabolic boundary (e=1.0001)", "[extreme][eccentricity][boundary]") { |
|
const double TIME_STEP = 60.0; |
|
|
|
SimulationState* sim = create_simulation(10, 3, 0, TIME_STEP); |
|
|
|
REQUIRE(load_system_config(sim, "tests/test_extreme_eccentricity.toml")); |
|
|
|
Spacecraft* hyperbolic = &sim->spacecraft[2]; |
|
CelestialBody* earth = &sim->bodies[0]; |
|
|
|
INFO("Testing spacecraft with e=" << hyperbolic->orbit.eccentricity); |
|
|
|
Vec3 pos; |
|
Vec3 vel; |
|
orbital_elements_to_cartesian(hyperbolic->orbit, earth->mass, &pos, &vel); |
|
|
|
double r = vec3_magnitude(pos); |
|
double v = vec3_magnitude(vel); |
|
|
|
double mu = G * earth->mass; |
|
double a = hyperbolic->orbit.semi_major_axis; |
|
double escape_velocity = sqrt(2.0 * mu / r); |
|
double circular_velocity = sqrt(mu / r); |
|
|
|
INFO("Radius: " << r << " m"); |
|
INFO("Velocity: " << v << " m/s"); |
|
INFO("Escape velocity: " << escape_velocity << " m/s"); |
|
INFO("Circular velocity: " << circular_velocity << " m/s"); |
|
INFO("Semi-major axis: " << a << " m"); |
|
|
|
double expected_v_squared = mu * (2.0 / r - 1.0 / a); |
|
double expected_v = sqrt(expected_v_squared); |
|
|
|
double v_error = fabs(v - expected_v); |
|
double relative_error = v_error / expected_v; |
|
|
|
INFO("Expected velocity: " << expected_v << " m/s"); |
|
INFO("Velocity error: " << v_error << " m/s (" << relative_error * 100.0 << "%)"); |
|
|
|
REQUIRE(relative_error < VELOCITY_TOLERANCE); |
|
REQUIRE(v > escape_velocity * 0.9); |
|
REQUIRE(a < 0.0); |
|
|
|
destroy_simulation(sim); |
|
} |
|
|
|
TEST_CASE("Velocity magnitude accuracy for extreme eccentricities", "[extreme][eccentricity][velocity]") { |
|
const double TIME_STEP = 60.0; |
|
|
|
SimulationState* sim = create_simulation(10, 3, 0, TIME_STEP); |
|
|
|
REQUIRE(load_system_config(sim, "tests/test_extreme_eccentricity.toml")); |
|
|
|
CelestialBody* earth = &sim->bodies[0]; |
|
|
|
for (int i = 0; i < sim->craft_count; i++) { |
|
Spacecraft* craft = &sim->spacecraft[i]; |
|
|
|
INFO("Spacecraft " << i << ": e=" << craft->orbit.eccentricity); |
|
|
|
double true_anomalies[] = {0.0, M_PI / 2.0, M_PI, 3.0 * M_PI / 2.0}; |
|
|
|
for (int j = 0; j < 4; j++) { |
|
double nu = true_anomalies[j]; |
|
craft->orbit.true_anomaly = nu; |
|
|
|
Vec3 pos; |
|
Vec3 vel; |
|
orbital_elements_to_cartesian(craft->orbit, earth->mass, &pos, &vel); |
|
|
|
double r = vec3_magnitude(pos); |
|
double v = vec3_magnitude(vel); |
|
|
|
double a = craft->orbit.semi_major_axis; |
|
double mu = G * earth->mass; |
|
|
|
double expected_v_squared = mu * (2.0 / r - 1.0 / a); |
|
|
|
if (expected_v_squared > 0.0) { |
|
double expected_v = sqrt(expected_v_squared); |
|
double v_error = fabs(v - expected_v); |
|
double relative_error = v_error / expected_v; |
|
|
|
INFO(" ν=" << nu << " rad: v=" << v << " m/s, error=" << relative_error * 100.0 << "%"); |
|
|
|
REQUIRE(relative_error < VELOCITY_TOLERANCE * 10.0); |
|
} |
|
} |
|
} |
|
|
|
destroy_simulation(sim); |
|
} |
|
|
|
TEST_CASE("Period calculation (or lack thereof) for e≥1", "[extreme][eccentricity][period]") { |
|
const double TIME_STEP = 60.0; |
|
|
|
SimulationState* sim = create_simulation(10, 3, 0, TIME_STEP); |
|
|
|
REQUIRE(load_system_config(sim, "tests/test_extreme_eccentricity.toml")); |
|
|
|
Spacecraft* high_e = &sim->spacecraft[0]; |
|
Spacecraft* near_parabolic = &sim->spacecraft[1]; |
|
Spacecraft* hyperbolic = &sim->spacecraft[2]; |
|
|
|
double a_e = high_e->orbit.semi_major_axis; |
|
double a_near = near_parabolic->orbit.semi_major_axis; |
|
double a_h = hyperbolic->orbit.semi_major_axis; |
|
|
|
INFO("Highly eccentric (e=0.99): a=" << a_e << " m"); |
|
INFO("Near-parabolic (e=0.9999): a=" << a_near << " m"); |
|
INFO("Hyperbolic (e=1.0001): a=" << a_h << " m"); |
|
|
|
REQUIRE(a_e > 0.0); |
|
REQUIRE(a_near > 0.0); |
|
REQUIRE(a_h < 0.0); |
|
|
|
destroy_simulation(sim); |
|
}
|
|
|