fix(ephemeris): include nutation in the sidereal frame
恒星黄道改为与 Swiss Ephemeris FLG_SIDEREAL 同一套含章动岁差。 产品默认路径不再用平岁差去减含章动的视位置。上升和宫头用同一个岁差。 校正身份升到 rectification-v5-matrix-scoring-12。 BUG-1275。未推送,未部署。v5 先验头名三格下降 1.3 个百分点,不调参。
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Freeze PyJHora 4.8.7 sidereal longitudes. Offline only.
|
||||
|
||||
Run from the repo root with a Python that has PyJHora 4.8.7:
|
||||
|
||||
python scripts/research/freeze_sidereal_nutation_pyjhora_fixture.py
|
||||
|
||||
Tests read the JSON and do not import this module.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.metadata
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
from contextlib import redirect_stdout
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path[:0] = [str(ROOT), str(ROOT / "scripts")]
|
||||
|
||||
import swisseph as swe # noqa: E402
|
||||
from jhora import const # noqa: E402
|
||||
from jhora.panchanga import drik # noqa: E402
|
||||
from jyotish_engine import compute_chart_data # noqa: E402
|
||||
|
||||
OUT = ROOT / "tests" / "fixtures" / "sidereal_nutation_pyjhora_487.json"
|
||||
MODES = {"lahiri": "LAHIRI", "raman": "RAMAN", "kp": "KP"}
|
||||
BODIES = (
|
||||
("Sun", const._SUN), ("Moon", const._MOON), ("Mars", const._MARS),
|
||||
("Mercury", const._MERCURY), ("Jupiter", const._JUPITER), ("Venus", const._VENUS),
|
||||
("Saturn", const._SATURN), ("Rahu", const._RAHU),
|
||||
)
|
||||
|
||||
|
||||
def _births() -> dict[str, dict]:
|
||||
public = json.loads((ROOT / "references" / "public_oracle_cases.json").read_text(encoding="utf-8"))
|
||||
births = {
|
||||
case["id"]: case["birth"]
|
||||
for case in public["cases"]
|
||||
if case["id"] in {"steve_jobs_1955_aa", "barack_obama_1961_aa", "einstein_1879_aa"}
|
||||
}
|
||||
special = json.loads((ROOT / "tests" / "fixtures" / "special_lagnas_pyjhora_487.json").read_text(encoding="utf-8"))
|
||||
births["fictional_reader_main"] = special["cases"]["fictional_reader_main"]["birth"]
|
||||
return births
|
||||
|
||||
|
||||
def _longitudes(birth: dict, mode: str) -> dict[str, float]:
|
||||
"""Same UTC conversion as drik.planetary_positions, via sidereal_longitude.
|
||||
|
||||
PyJHora 4.8.7's planetary_positions calls dict.index on planet_list and
|
||||
raises AttributeError, so the wrapper cannot be the frozen source.
|
||||
"""
|
||||
local_hour = birth["hour"] + birth["minute"] / 60.0 + birth.get("second", 0) / 3600.0
|
||||
jd_local = swe.julday(birth["year"], birth["month"], birth["day"], local_hour)
|
||||
jd_ut = jd_local - float(birth["tz"]) / 24.0
|
||||
with redirect_stdout(io.StringIO()):
|
||||
drik.set_ayanamsa_mode(mode)
|
||||
longitudes = {
|
||||
name: float(drik.sidereal_longitude(jd_ut, planet)) % 360.0
|
||||
for name, planet in BODIES
|
||||
}
|
||||
longitudes["Ketu"] = float(drik.ketu(longitudes["Rahu"])) % 360.0
|
||||
return longitudes
|
||||
|
||||
|
||||
def _gap(left: float, right: float) -> float:
|
||||
return abs(((left - right + 180.0) % 360.0) - 180.0)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
cases = {}
|
||||
worst = 0.0
|
||||
for case_id, birth in _births().items():
|
||||
by_mode = {}
|
||||
for name, mode in MODES.items():
|
||||
frozen = _longitudes(birth, mode)
|
||||
chart, *_rest = compute_chart_data(
|
||||
birth["year"], birth["month"], birth["day"], birth["hour"], birth["minute"],
|
||||
birth["lat"], birth["lon"], birth["tz"], node_mode="true",
|
||||
second=birth.get("second", 0), ayanamsa_name=name,
|
||||
)
|
||||
for planet, longitude in frozen.items():
|
||||
worst = max(worst, _gap(chart["planets"][planet]["degree_raw"], longitude))
|
||||
by_mode[name] = frozen
|
||||
cases[case_id] = {"ayanamsa": by_mode}
|
||||
payload = {
|
||||
"pyjhora_version": importlib.metadata.version("PyJHora"),
|
||||
"generator": "python scripts/research/freeze_sidereal_nutation_pyjhora_fixture.py",
|
||||
"generated_on": "2026-10-08",
|
||||
"node_mode": "true",
|
||||
"max_abs_difference_degrees": worst,
|
||||
"note": "Frozen from drik.sidereal_longitude. PyJHora 4.8.7 planetary_positions raises AttributeError because planet_list is a dict. Rahu body is const._RAHU (Swiss 11). Differences are recorded, not a second runtime.",
|
||||
"cases": cases,
|
||||
}
|
||||
OUT.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", newline="\n")
|
||||
print(OUT.relative_to(ROOT).as_posix())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -30,8 +30,8 @@ from scripts.research.sealed_holdout_rerun import (
|
||||
OFFSETS = (-30, -20, -15, -10, -8, -5, -3, 0, 3, 5, 8, 10, 15, 20, 30)
|
||||
RADII = (15, 30, 60)
|
||||
MINUTE_STEP = 1
|
||||
FREEZE = ROOT / "docs/research/reported_offset_upstream_sync6_2026_10_07.freeze.json"
|
||||
REPORT = ROOT / "docs/research/reported_offset_upstream_sync6_2026_10_07.json"
|
||||
FREEZE = ROOT / "docs/research/reported_offset_ephemeris_nutation_2026_10_08.freeze.json"
|
||||
REPORT = ROOT / "docs/research/reported_offset_ephemeris_nutation_2026_10_08.json"
|
||||
LEGACY_REPORT = ROOT / "docs/research/reported_offset_2026_09_20.json"
|
||||
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ from scripts.minute_rectification_feature_facts_v4 import build_feature_fact_row
|
||||
from scripts.minute_rectification_holdout_validator import validate
|
||||
|
||||
DATASET = ROOT / "references/real_case_calibration/minute_rectification_holdout_v3.json"
|
||||
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync6_2026_10_07.freeze.json"
|
||||
REPORT = ROOT / "docs/research/sealed_holdout_rerun_upstream_sync6_2026_10_07.json"
|
||||
FREEZE = ROOT / "docs/research/sealed_holdout_rerun_ephemeris_nutation_2026_10_08.freeze.json"
|
||||
REPORT = ROOT / "docs/research/sealed_holdout_rerun_ephemeris_nutation_2026_10_08.json"
|
||||
LEGACY_REPORT = ROOT / "docs/research/sealed_holdout_rerun_2026_09_20.json"
|
||||
ARCHIVE = ROOT / "docs/research/history/rectification_pre_cross_midnight_2026_09_20"
|
||||
PRODUCTION_FILES = [
|
||||
|
||||
Reference in New Issue
Block a user