import math
import random
from benchmarks.comparative.tasks.base import BenchmarkTask
R_EARTH = 6378137.0
GM_EARTH = 3.986004418e14
_FIXED_EPOCH_JD = 2460310.5 _FIXED_STATE_ECI = [
6_525_919.0,
1_710_416.0,
2_508_886.0,
-2_682.6,
7_209.5,
-1_953.7,
]
_N_SAMPLES = 100
def _random_leo_state_eci(rng: random.Random) -> dict:
a = R_EARTH + rng.uniform(400e3, 1500e3)
e = rng.uniform(0.001, 0.02)
i = math.radians(rng.uniform(0.0, 180.0))
raan = math.radians(rng.uniform(0.0, 360.0))
argp = math.radians(rng.uniform(0.0, 360.0))
nu = math.radians(rng.uniform(0.0, 360.0))
p = a * (1.0 - e * e)
r = p / (1.0 + e * math.cos(nu))
r_pqw = [r * math.cos(nu), r * math.sin(nu), 0.0]
v_mag = math.sqrt(GM_EARTH / p)
v_pqw = [-v_mag * math.sin(nu), v_mag * (e + math.cos(nu)), 0.0]
cos_raan, sin_raan = math.cos(raan), math.sin(raan)
cos_argp, sin_argp = math.cos(argp), math.sin(argp)
cos_i, sin_i = math.cos(i), math.sin(i)
r11 = cos_raan * cos_argp - sin_raan * sin_argp * cos_i
r12 = -(cos_raan * sin_argp + sin_raan * cos_argp * cos_i)
r21 = sin_raan * cos_argp + cos_raan * sin_argp * cos_i
r22 = -(sin_raan * sin_argp - cos_raan * cos_argp * cos_i)
r31 = sin_argp * sin_i
r32 = cos_argp * sin_i
x = r11 * r_pqw[0] + r12 * r_pqw[1]
y = r21 * r_pqw[0] + r22 * r_pqw[1]
z = r31 * r_pqw[0] + r32 * r_pqw[1]
vx = r11 * v_pqw[0] + r12 * v_pqw[1]
vy = r21 * v_pqw[0] + r22 * v_pqw[1]
vz = r31 * v_pqw[0] + r32 * v_pqw[1]
return {
"jd": _FIXED_EPOCH_JD + rng.uniform(0.0, 365.0),
"state_eci": [x, y, z, vx, vy, vz],
}
def _ic_swept_force_params(seed: int, n: int, base: dict) -> dict:
rng = random.Random(seed)
cases = [_random_leo_state_eci(rng) for _ in range(n)]
out = dict(base)
out.pop("jd", None)
out.pop("state_eci", None)
out["cases"] = cases
out["n_samples"] = 1
return out
def _altitude_km_from_state(state: list[float]) -> float:
r = math.sqrt(state[0] ** 2 + state[1] ** 2 + state[2] ** 2)
return (r - R_EARTH) / 1000.0
class _AccelTaskBase(BenchmarkTask):
@property
def module(self) -> str:
return "force_model"
@property
def languages(self) -> list[str]:
return ["python", "rust", "java", "gmat"]
def _base_params(self) -> dict:
return {
"jd": _FIXED_EPOCH_JD,
"state_eci": list(_FIXED_STATE_ECI),
"n_samples": _N_SAMPLES,
}
def _accuracy_base(self) -> dict:
return {}
def generate_accuracy_samples(self, seed: int, n: int) -> dict:
return _ic_swept_force_params(seed, n, self._accuracy_base())
def accuracy_sample_key(self, params: dict) -> dict:
if "state_eci" in params and isinstance(params["state_eci"], list):
return {"altitude_km": _altitude_km_from_state(params["state_eci"])}
return {}
class AccelPointMassGravityTask(_AccelTaskBase):
@property
def name(self) -> str:
return "force_model.accel_point_mass_gravity"
@property
def description(self) -> str:
return "Evaluate point-mass gravity acceleration at a fixed LEO state"
def generate_params(self, seed: int) -> dict:
return self._base_params()
class AccelSphericalHarmonics20Task(_AccelTaskBase):
@property
def name(self) -> str:
return "force_model.accel_spherical_harmonics_20"
@property
def description(self) -> str:
return "Evaluate 20x20 spherical-harmonic gravity acceleration at a fixed LEO state"
@property
def languages(self) -> list[str]:
return ["python", "rust", "java", "gmat", "nyx"]
def generate_params(self, seed: int) -> dict:
p = self._base_params()
p["degree"] = 20
p["order"] = 20
return p
def _accuracy_base(self) -> dict:
return {"degree": 20, "order": 20}
class AccelSphericalHarmonics80Task(_AccelTaskBase):
@property
def name(self) -> str:
return "force_model.accel_spherical_harmonics_80"
@property
def description(self) -> str:
return "Evaluate 80x80 spherical-harmonic gravity acceleration at a fixed LEO state"
@property
def languages(self) -> list[str]:
return ["python", "rust", "java", "gmat", "nyx"]
def generate_params(self, seed: int) -> dict:
p = self._base_params()
p["degree"] = 80
p["order"] = 80
return p
def _accuracy_base(self) -> dict:
return {"degree": 80, "order": 80}
class AccelThirdBodySunTask(_AccelTaskBase):
@property
def name(self) -> str:
return "force_model.accel_third_body_sun"
@property
def description(self) -> str:
return "Evaluate Sun third-body acceleration (DE440s) at a fixed LEO state"
@property
def languages(self) -> list[str]:
return ["python", "rust", "java", "gmat", "nyx"]
def generate_params(self, seed: int) -> dict:
return self._base_params()
class AccelThirdBodyMoonTask(_AccelTaskBase):
@property
def name(self) -> str:
return "force_model.accel_third_body_moon"
@property
def description(self) -> str:
return "Evaluate Moon third-body acceleration (DE440s) at a fixed LEO state"
@property
def languages(self) -> list[str]:
return ["python", "rust", "java", "gmat", "nyx"]
def generate_params(self, seed: int) -> dict:
return self._base_params()