import math
from benchmarks.comparative.implementations.gmat.base import (
build_task_result,
time_iterations,
)
_DUMMY_VX_KMS = 7.5
def _earth_params():
import gmatpy as gmat
ss = gmat.GetSolarSystem()
earth = ss.GetBody("Earth")
a = earth.GetEquatorialRadius() f = earth.GetFlattening()
return a, f, 2.0 * f - f * f
def _geocentric_r_km(lat_deg, lon_deg, alt_m, a, e2):
alt_km = alt_m / 1000.0
lat_r = math.radians(lat_deg)
lon_r = math.radians(lon_deg)
sin_lat = math.sin(lat_r)
cos_lat = math.cos(lat_r)
N = a / math.sqrt(1.0 - e2 * sin_lat * sin_lat)
x = (N + alt_km) * cos_lat * math.cos(lon_r)
y = (N + alt_km) * cos_lat * math.sin(lon_r)
z = (N * (1.0 - e2) + alt_km) * sin_lat
return math.sqrt(x * x + y * y + z * z)
def _alt_from_r_lat(r_km, lat_geodetic_deg, a, e2):
phi = math.radians(lat_geodetic_deg)
sin_phi = math.sin(phi)
cos_phi = math.cos(phi)
N = a / math.sqrt(1.0 - e2 * sin_phi * sin_phi)
p = N * (1.0 - e2 * sin_phi * sin_phi) q = N * N * (cos_phi * cos_phi + (1.0 - e2) * (1.0 - e2) * sin_phi * sin_phi)
disc = r_km * r_km - q + p * p
return -p + math.sqrt(disc)
def geodetic_to_ecef(params: dict, iterations: int):
import gmatpy as gmat
a, f, e2 = _earth_params()
scu = gmat.StateConversionUtil
pts_planetodetic = []
for lon_deg, lat_deg, alt_m in params["points"]:
r_km = _geocentric_r_km(lat_deg, lon_deg, alt_m, a, e2)
pts_planetodetic.append((r_km, lon_deg, lat_deg))
def run():
out = []
for r_km, lon_deg, lat_deg in pts_planetodetic:
rv_pd = gmat.Rvector6(r_km, lon_deg, lat_deg, _DUMMY_VX_KMS, 0.0, 0.0)
rv_cart = scu.PlanetodeticToCartesian(rv_pd, f, a)
out.append([
float(rv_cart.GetElement(0)) * 1000.0,
float(rv_cart.GetElement(1)) * 1000.0,
float(rv_cart.GetElement(2)) * 1000.0,
])
return out
times, results = time_iterations(run, iterations)
return build_task_result(
"coordinates.geodetic_to_ecef",
iterations,
times,
results,
extra_metadata={
"ellipsoid": "GMAT Earth",
"gmat_eq_radius_km": a,
"gmat_flattening": f,
"accuracy_note": (
"GMAT eq_radius (6378.1363 km) differs from WGS84 (6378.137 km) "
"by -0.7 m; PlanetodeticToCartesian has ~0.18 m algorithm error "
"vs direct WGS84 formula. Both are intrinsic to GMAT."
),
},
)
_R_WGS84_M = 6378137.0
_R_WGS84_KM = _R_WGS84_M / 1000.0
def ecef_to_geodetic(params: dict, iterations: int):
import gmatpy as gmat
a, f, e2 = _earth_params()
scu = gmat.StateConversionUtil
pts_km = [
[x / 1000.0 for x in p]
for p in params["points"]
]
def run():
out = []
for x_km, y_km, z_km in pts_km:
rv_cart = gmat.Rvector6(x_km, y_km, z_km, _DUMMY_VX_KMS, 0.0, 0.0)
rv_pd = scu.CartesianToPlanetodetic(rv_cart, f, a)
r_km = float(rv_pd.GetElement(0))
lon_deg = float(rv_pd.GetElement(1))
lat_deg = float(rv_pd.GetElement(2))
alt_m = _alt_from_r_lat(r_km, lat_deg, a, e2) * 1000.0
out.append([lon_deg, lat_deg, alt_m])
return out
times, results = time_iterations(run, iterations)
return build_task_result(
"coordinates.ecef_to_geodetic",
iterations,
times,
results,
extra_metadata={
"ellipsoid": "GMAT Earth",
"gmat_eq_radius_km": a,
"gmat_flattening": f,
"accuracy_note": (
"GMAT eq_radius (6378.1363 km) differs from WGS84 (6378.137 km) "
"by -0.7 m. Both are intrinsic to GMAT's Earth model."
),
},
)
def geocentric_to_ecef(params: dict, iterations: int):
import gmatpy as gmat
scu = gmat.StateConversionUtil
pts_spherical = []
for lon_deg, lat_geo_deg, alt_m in params["points"]:
r_km = (_R_WGS84_M + alt_m) / 1000.0
pts_spherical.append((r_km, lon_deg, lat_geo_deg))
def run():
out = []
for r_km, lon_deg, lat_geo_deg in pts_spherical:
rv_sph = gmat.Rvector6(r_km, lon_deg, lat_geo_deg, _DUMMY_VX_KMS, 0.0, 0.0)
rv_cart = scu.SphericalRADECToCartesian(rv_sph)
out.append([
float(rv_cart.GetElement(0)) * 1000.0,
float(rv_cart.GetElement(1)) * 1000.0,
float(rv_cart.GetElement(2)) * 1000.0,
])
return out
times, results = time_iterations(run, iterations)
return build_task_result(
"coordinates.geocentric_to_ecef",
iterations,
times,
results,
extra_metadata={
"r_ref_m": _R_WGS84_M,
"accuracy_note": (
"Pure spherical trig via SphericalRADECToCartesian; machine-epsilon "
"accuracy. Uses Java-compatible R_WGS84 = 6378137.0 m as altitude "
"reference so results are directly comparable to the Java baseline."
),
},
)
def ecef_to_geocentric(params: dict, iterations: int):
import gmatpy as gmat
scu = gmat.StateConversionUtil
pts_km = [
[v / 1000.0 for v in p]
for p in params["points"]
]
def run():
out = []
for x_km, y_km, z_km in pts_km:
rv_cart = gmat.Rvector6(x_km, y_km, z_km, _DUMMY_VX_KMS, 0.0, 0.0)
rv_sph = scu.CartesianToSphericalRADEC(rv_cart)
r_km = float(rv_sph.GetElement(0))
lon_deg = float(rv_sph.GetElement(1))
lat_geo_deg = float(rv_sph.GetElement(2))
alt_m = r_km * 1000.0 - _R_WGS84_M
out.append([lon_deg, lat_geo_deg, alt_m])
return out
times, results = time_iterations(run, iterations)
return build_task_result(
"coordinates.ecef_to_geocentric",
iterations,
times,
results,
extra_metadata={
"r_ref_m": _R_WGS84_M,
"accuracy_note": (
"Pure spherical trig via CartesianToSphericalRADEC; machine-epsilon "
"accuracy. Uses Java-compatible R_WGS84 = 6378137.0 m as altitude "
"reference so results are directly comparable to the Java baseline."
),
},
)