from __future__ import annotations
import json
import re
from pathlib import Path
import erfa
SAMPLES: tuple[float, ...] = (
-1.0,
-0.5,
-0.24,
-0.1,
-0.01,
0.0,
0.01,
0.1,
0.2,
0.24,
0.5,
1.0,
)
def fundamental_arguments(t: float) -> dict[str, float]:
return {
"l": float(erfa.fal03(t)),
"l_prime": float(erfa.falp03(t)),
"f": float(erfa.faf03(t)),
"d": float(erfa.fad03(t)),
"omega": float(erfa.faom03(t)),
"l_me": float(erfa.fame03(t)),
"l_ve": float(erfa.fave03(t)),
"l_e": float(erfa.fae03(t)),
"l_ma": float(erfa.fama03(t)),
"l_j": float(erfa.faju03(t)),
"l_sa": float(erfa.fasa03(t)),
"l_u": float(erfa.faur03(t)),
"l_ne": float(erfa.fane03(t)),
"p_a": float(erfa.fapa03(t)),
}
def precession_fukushima_williams(t: float) -> dict[str, float]:
J2000_JD = 2451545.0
offset_days = t * 36525.0
gamb, phib, psib, epsa = erfa.pfw06(J2000_JD, offset_days)
return {
"gamma_bar": float(gamb),
"phi_bar": float(phib),
"psi_bar": float(psib),
"eps_a": float(epsa),
}
def cip_xys(t: float) -> dict[str, float]:
J2000_JD = 2451545.0
offset_days = t * 36525.0
x, y = erfa.xy06(J2000_JD, offset_days)
s = erfa.s06(J2000_JD, offset_days, x, y)
return {
"x": float(x),
"y": float(y),
"s": float(s),
}
def gcrs_to_cirs_matrix(t: float) -> list[list[float]]:
J2000_JD = 2451545.0
offset_days = t * 36525.0
x, y = erfa.xy06(J2000_JD, offset_days)
s = erfa.s06(J2000_JD, offset_days, x, y)
m = erfa.c2ixys(x, y, s)
return [[float(v) for v in row] for row in m]
def gcrs_to_itrs_matrix_zero_eop(t: float) -> dict:
J2000_JD = 2451545.0
offset_days = t * 36525.0
x, y = erfa.xy06(J2000_JD, offset_days)
s = erfa.s06(J2000_JD, offset_days, x, y)
rc2i = erfa.c2ixys(x, y, s)
era = erfa.era00(J2000_JD, offset_days)
rc2tirs = erfa.rz(era, rc2i)
sp = erfa.sp00(J2000_JD, offset_days)
rpom = erfa.pom00(0.0, 0.0, sp)
rc2t = rpom @ rc2tirs
return {
"era": float(era),
"sp": float(sp),
"matrix": [[float(v) for v in row] for row in rc2t],
}
def main() -> None:
samples = []
for t in SAMPLES:
samples.append(
{
"t_tt_centuries_from_j2000": t,
"fundamental_arguments": fundamental_arguments(t),
"precession_fukushima_williams": precession_fukushima_williams(t),
"cip_xys": cip_xys(t),
"gcrs_to_cirs_matrix": gcrs_to_cirs_matrix(t),
"gcrs_to_itrs_matrix_zero_eop": gcrs_to_itrs_matrix_zero_eop(t),
}
)
fixture = {
"description": (
"IAU 2006 / 2000A_R06 reference values generated from ERFA "
"(liberfa/erfa), a BSD-3-Clause fork of IAU SOFA. Used by "
"arika/tests/iau2006_vs_erfa.rs as an independent oracle "
"for the pure-Rust IAU 2006 implementation in "
"arika/src/earth/iau2006/."
),
"source": f"pyerfa {erfa.__version__}",
"generator": "arika/tools/generate_iau2006_reference.py",
"convention": "IAU 2006 / 2000A_R06, IERS Conventions 2010 (TN36)",
"independent_variable": "t = TT Julian centuries since J2000.0",
"units": {
"fundamental_arguments": "rad (each value is fmod'd modulo 2*pi)",
"precession_fukushima_williams": "rad",
"cip_xys": "rad",
"gcrs_to_cirs_matrix": "dimensionless, row-major 3x3 orthogonal",
"gcrs_to_itrs_matrix_zero_eop": "dimensionless matrix + era (rad) + sp (rad)",
},
"samples": samples,
}
arika_root = Path(__file__).resolve().parent.parent
out_path = arika_root / "tests" / "fixtures" / "iau2006_erfa_reference.json"
out_path.parent.mkdir(parents=True, exist_ok=True)
raw = json.dumps(fixture, indent=2)
normalised = re.sub(r"(e[+-])0(\d)", r"\1\2", raw)
out_path.write_text(normalised + "\n")
print(f"Wrote {len(samples)} samples to {out_path}")
if __name__ == "__main__":
main()