"""Sidereal Sun and Moon on the chart function's frame. One process import. Ayanamsa is recomputed per instant so a year-long search does not freeze the precession. This is not the apparent path. """ from __future__ import annotations import swisseph as swe try: from jyotish_engine import _apply_ayanamsa, _sidereal_calculation_profile except ImportError: # pragma: no cover - package import from scripts.jyotish_engine import _apply_ayanamsa, _sidereal_calculation_profile _SPEED = getattr(swe, "FLG_SPEED", 256) class SiderealFrame: def __init__(self, ayanamsa_name: str, node_mode: str = "mean") -> None: self.ayanamsa_name = str(ayanamsa_name or "lahiri") self.node_mode = node_mode if node_mode in ("mean", "true") else "mean" _apply_ayanamsa(self.ayanamsa_name) def sun_moon(self, jd: float) -> tuple[float, float]: _mode, calc_flags, ayanamsa = _sidereal_calculation_profile(float(jd), "legacy") flags = calc_flags | _SPEED sun = _body(float(jd), swe.SUN, flags, ayanamsa) moon = _body(float(jd), swe.MOON, flags, ayanamsa) return sun, moon def _body(jd: float, body: int, flags: int, ayanamsa: float) -> float: pos, ret = swe.calc_ut(jd, body, flags) if ret < 0: raise RuntimeError(f"swisseph calc_ut failed for body {body} at jd {jd}: code {ret}") return (float(pos[0]) - float(ayanamsa)) % 360.0 def birth_jd(year: int, month: int, day: int, hour: float, tz_hours: float) -> float: """Same Julian day the chart function uses: local clock minus the offset.""" return float(swe.julday(int(year), int(month), int(day), float(hour) - float(tz_hours))) def year_start_jd(year: int) -> float: return float(swe.julday(int(year), 1, 1, 0.0))