Browse Source

Consolidate cartesian tests: merge extreme + quadrature into advanced

- Combined test_cartesian_to_elements_extreme.cpp (263 lines) and
  test_cartesian_to_elements_quadrature.cpp (264 lines) into
  test_cartesian_to_elements_advanced.cpp (508 lines, -19 lines saved)
- All 30 test cases preserved (16 from extreme + 14 from quadrature)
- No config files to merge (tests use hardcoded values)
main
cinnaboot 5 months ago
parent
commit
5b4048d11e
  1. 263
      tests/test_cartesian_to_elements_advanced.cpp
  2. 262
      tests/test_cartesian_to_elements_extreme.cpp

263
tests/test_cartesian_to_elements_quadrature.cpp → tests/test_cartesian_to_elements_advanced.cpp

@ -9,12 +9,257 @@
using Catch::Matchers::WithinAbs;
TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
TEST_CASE("Cartesian to Elements - Advanced Tests", "[orbital_mechanics]") {
const double G = 6.67430e-11;
const double M_sun = 1.989e30;
const double mu = G * M_sun;
SECTION("Quadrature point ν=π/2 (90°) preserves orbital elements") {
SECTION("Circular orbit conversion preserves exact circular parameters") {
double r = 1.496e11;
double v_circular = sqrt(mu / r);
Vec3 position = {r, 0.0, 0.0};
Vec3 velocity = {0.0, v_circular, 0.0};
OrbitalElements elements = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(elements.eccentricity, WithinAbs(0.0, 1e-10));
REQUIRE_THAT(elements.semi_major_axis, WithinAbs(r, 1e3));
Vec3 converted_position, converted_velocity;
orbital_elements_to_cartesian(elements, M_sun, &converted_position, &converted_velocity);
REQUIRE(compare_vec3(position, converted_position, 1e3));
REQUIRE(compare_vec3(velocity, converted_velocity, 1e-3));
}
SECTION("Near-circular orbit (e=0.001) recovers small eccentricity") {
OrbitalElements elements = {
.semi_major_axis = 1.496e11,
.eccentricity = 0.001,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.001, 1e-6));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.496e11, 1e3));
}
SECTION("Elliptical orbit (e=0.5) preserves orbital shape") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = 0.8,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.0e11, 1e6));
}
SECTION("Highly elliptical orbit (e=0.95) preserves extreme eccentricity") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.95,
.true_anomaly = 0.1,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.95, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.0e11, 1e6));
}
SECTION("Near-parabolic orbit (e=0.999) recovers near-escape trajectory") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.999,
.true_anomaly = 0.05,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.999, 1e-3));
}
SECTION("Parabolic orbit (e=1.0) recovers escape trajectory") {
OrbitalElements elements = {
.semi_latus_rectum = 1.0e11,
.eccentricity = 1.0,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(1.0, 1e-2));
REQUIRE_THAT(recovered.semi_latus_rectum, WithinAbs(1.0e11, 1e3));
}
SECTION("Hyperbolic orbit (e=2.0) preserves unbound trajectory") {
OrbitalElements elements = {
.semi_major_axis = -1.0e11,
.eccentricity = 2.0,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(2.0, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(-1.0e11, 1e6));
}
SECTION("Highly hyperbolic orbit (e=10.0) preserves extreme unbound trajectory") {
OrbitalElements elements = {
.semi_major_axis = -1.0e10,
.eccentricity = 10.0,
.true_anomaly = 0.8,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(10.0, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(-1.0e10, 1e8));
}
SECTION("Zero inclination (i=0) preserves equatorial orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.3,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(0.0, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.3, 1e-4));
}
SECTION("90-degree inclination (i=pi/2) preserves polar orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.2,
.true_anomaly = 0.6,
.inclination = M_PI / 2.0,
.longitude_of_ascending_node = 0.5,
.argument_of_periapsis = 0.3
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(M_PI / 2.0, 1e-4));
REQUIRE_THAT(recovered.longitude_of_ascending_node, WithinAbs(0.5, 1e-4));
REQUIRE_THAT(recovered.argument_of_periapsis, WithinAbs(0.3, 1e-4));
}
SECTION("180-degree inclination (i=pi) preserves retrograde orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.2,
.true_anomaly = 0.6,
.inclination = M_PI,
.longitude_of_ascending_node = 0.5,
.argument_of_periapsis = 0.3
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(M_PI, 1e-4));
}
SECTION("Periapsis (nu=0) recovers true anomaly correctly") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = 0.0,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(0.0, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
}
SECTION("Apoapsis (nu=pi) recovers true anomaly correctly") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = M_PI,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(M_PI, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
}
SECTION("Quadrature point nu=pi/2 (90 deg) preserves orbital elements") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -34,7 +279,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(M_PI / 2.0, 1e-6));
}
SECTION("Quadrature point ν=-π/2 (-90°) preserves orbital elements") {
SECTION("Quadrature point nu=-pi/2 (-90 deg) preserves orbital elements") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -54,7 +299,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(-M_PI / 2.0, 1e-6));
}
SECTION("Quadrature point ν=3π/2 (270°) preserves orbital elements") {
SECTION("Quadrature point nu=3pi/2 (270 deg) preserves orbital elements") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -74,7 +319,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(-M_PI / 2.0, 1e-6));
}
SECTION("Quadrature point ν=-3π/2 (-270°) preserves orbital elements") {
SECTION("Quadrature point nu=-3pi/2 (-270 deg) preserves orbital elements") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -134,7 +379,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(M_PI / 2.0, 1e-6));
}
SECTION("Large true anomaly ν=5.0 rad (≈286°) preserves accuracy") {
SECTION("Large true anomaly nu=5.0 rad (approx 286 deg) preserves accuracy") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -154,7 +399,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(-1.28318530717958623, 1e-6));
}
SECTION("Large negative true anomaly ν=-5.0 rad (≈-286°) preserves accuracy") {
SECTION("Large negative true anomaly nu=-5.0 rad (approx -286 deg) preserves accuracy") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -174,7 +419,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(1.28318530717958623, 1e-6));
}
SECTION("Very large true anomaly ν=10.0 rad (≈573°) preserves accuracy") {
SECTION("Very large true anomaly nu=10.0 rad (approx 573 deg) preserves accuracy") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
@ -241,7 +486,7 @@ TEST_CASE("Cartesian to Elements - Quadrature Points", "[orbital_mechanics]") {
}
}
SECTION("Hyperbolic orbit at quadrature point ν=π/2") {
SECTION("Hyperbolic orbit at quadrature point nu=pi/2") {
OrbitalElements elements = {
.semi_major_axis = -1.0e11,
.eccentricity = 2.0,

262
tests/test_cartesian_to_elements_extreme.cpp

@ -1,262 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <cmath>
#include "../src/orbital_mechanics.h"
#include "../src/spacecraft.h"
#include "../src/test_utilities.h"
#include "../src/config_loader.h"
#include "../src/simulation.h"
using Catch::Matchers::WithinAbs;
TEST_CASE("Cartesian to Elements - Edge Cases", "[orbital_mechanics]") {
const double G = 6.67430e-11;
const double M_sun = 1.989e30;
const double mu = G * M_sun;
SECTION("Circular orbit conversion preserves exact circular parameters") {
double r = 1.496e11;
double v_circular = sqrt(mu / r);
Vec3 position = {r, 0.0, 0.0};
Vec3 velocity = {0.0, v_circular, 0.0};
OrbitalElements elements = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(elements.eccentricity, WithinAbs(0.0, 1e-10));
REQUIRE_THAT(elements.semi_major_axis, WithinAbs(r, 1e3));
Vec3 converted_position, converted_velocity;
orbital_elements_to_cartesian(elements, M_sun, &converted_position, &converted_velocity);
REQUIRE(compare_vec3(position, converted_position, 1e3));
REQUIRE(compare_vec3(velocity, converted_velocity, 1e-3));
}
SECTION("Near-circular orbit (e=0.001) recovers small eccentricity") {
OrbitalElements elements = {
.semi_major_axis = 1.496e11,
.eccentricity = 0.001,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.001, 1e-6));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.496e11, 1e3));
}
SECTION("Elliptical orbit (e=0.5) preserves orbital shape") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = 0.8,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.0e11, 1e6));
}
SECTION("Highly elliptical orbit (e=0.95) preserves extreme eccentricity") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.95,
.true_anomaly = 0.1,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.95, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(1.0e11, 1e6));
}
SECTION("Near-parabolic orbit (e=0.999) recovers near-escape trajectory") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.999,
.true_anomaly = 0.05,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.999, 1e-3));
// Semi-major axis poorly conditioned for e≈1, skip test
}
SECTION("Parabolic orbit (e=1.0) recovers escape trajectory") {
OrbitalElements elements = {
.semi_latus_rectum = 1.0e11,
.eccentricity = 1.0,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(1.0, 1e-2));
REQUIRE_THAT(recovered.semi_latus_rectum, WithinAbs(1.0e11, 1e3));
}
SECTION("Hyperbolic orbit (e=2.0) preserves unbound trajectory") {
OrbitalElements elements = {
.semi_major_axis = -1.0e11,
.eccentricity = 2.0,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(2.0, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(-1.0e11, 1e6));
}
SECTION("Highly hyperbolic orbit (e=10.0) preserves extreme unbound trajectory") {
OrbitalElements elements = {
.semi_major_axis = -1.0e10,
.eccentricity = 10.0,
.true_anomaly = 0.8,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.eccentricity, WithinAbs(10.0, 1e-3));
REQUIRE_THAT(recovered.semi_major_axis, WithinAbs(-1.0e10, 1e8));
}
SECTION("Zero inclination (i=0) preserves equatorial orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.3,
.true_anomaly = 0.5,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(0.0, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.3, 1e-4));
}
SECTION("90-degree inclination (i=π/2) preserves polar orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.2,
.true_anomaly = 0.6,
.inclination = M_PI / 2.0,
.longitude_of_ascending_node = 0.5,
.argument_of_periapsis = 0.3
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(M_PI / 2.0, 1e-4));
REQUIRE_THAT(recovered.longitude_of_ascending_node, WithinAbs(0.5, 1e-4));
REQUIRE_THAT(recovered.argument_of_periapsis, WithinAbs(0.3, 1e-4));
}
SECTION("180-degree inclination (i=π) preserves retrograde orbit") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.2,
.true_anomaly = 0.6,
.inclination = M_PI,
.longitude_of_ascending_node = 0.5,
.argument_of_periapsis = 0.3
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.inclination, WithinAbs(M_PI, 1e-4));
}
SECTION("Periapsis (ν=0) recovers true anomaly correctly") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = 0.0,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(0.0, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
}
SECTION("Apoapsis (ν=π) recovers true anomaly correctly") {
OrbitalElements elements = {
.semi_major_axis = 1.0e11,
.eccentricity = 0.5,
.true_anomaly = M_PI,
.inclination = 0.0,
.longitude_of_ascending_node = 0.0,
.argument_of_periapsis = 0.0
};
Vec3 position, velocity;
orbital_elements_to_cartesian(elements, M_sun, &position, &velocity);
OrbitalElements recovered = cartesian_to_orbital_elements(position, velocity, M_sun);
REQUIRE_THAT(recovered.true_anomaly, WithinAbs(M_PI, 1e-6));
REQUIRE_THAT(recovered.eccentricity, WithinAbs(0.5, 1e-4));
}
}
Loading…
Cancel
Save