Files
Jyotisha/scripts/research_timing/frame.py
T
jesse-uxandGrok (agent loop) d45e65a9ec 完整数据版补上研究口径的推运、次小运和细分盘(#92)。
研究章在渲染时计算,不写入资料包。四种星座大运次小运和 Kalachakra 第三层不改原来的主运、子运。D81、D108、D144 只留在研究章。

自测:test_research_timing、星座大运、域读取、卫生预算、真恒星、jhora 扫描、API 增长、六章标题、英文版。三张虚构盘中英出稿都低于 180 秒。PyJHora 已导入但未做逐层对照。

Co-Authored-By: Grok (agent loop)
2026-10-23 18:20:44 +08:00

47 lines
1.7 KiB
Python

"""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))