fix(shadbala): Ayana hemisphere after wrap, civil-weekday hora lord, continuous mean motion, short-arc Chesta midpoint (upstream 0afa2780)
Ported from yinduzhanxing 0afa2780 (algorithm hunks and its four regression tests; the PyJHora / profile-metadata hunks do not apply to our file). The archived-PyJHora Kala test follows upstream's rewrite. The V.P. Jain benchmark expectations still need the three-column update (follow-up in this branch). TASK-upstream-sync4-20261002 T3. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
96767418ee
commit
08376cf0a8
@@ -0,0 +1,31 @@
|
||||
import pytest
|
||||
|
||||
from scripts.shadbala import chesta_from_longitudes as circular_chesta
|
||||
|
||||
|
||||
@pytest.mark.parametrize("rotation", range(0, 360, 15))
|
||||
def test_strength_does_not_depend_on_choice_of_zodiac_origin(rotation):
|
||||
# Mean350/true10 must average to0, not180. Apogee180 gives full strength.
|
||||
angles = [(angle + rotation) % 360 for angle in (350, 10, 180)]
|
||||
assert circular_chesta(*angles) == 60
|
||||
|
||||
|
||||
def test_midpoint_is_continuous_across_zero_and_full_turns():
|
||||
assert circular_chesta(359.9999, 10, 180) == circular_chesta(.0001, 10, 180)
|
||||
assert circular_chesta(-10, 370, 540) == circular_chesta(350, 10, 180)
|
||||
|
||||
|
||||
def test_does_not_guess_an_antipodal_branch():
|
||||
with pytest.raises(ValueError, match="Antipodal"):
|
||||
circular_chesta(0, 180, 90)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mean,true,apogee,expected", [
|
||||
(266.34, 229.50, 181.23, 22.23),
|
||||
(181.23, 181.52, 174.49, 2.29),
|
||||
(66.91, 84.01, 181.23, 35.26),
|
||||
(181.23, 171.16, 158.35, 5.95),
|
||||
(111.23, 124.39, 181.23, 21.14),
|
||||
])
|
||||
def test_published_non_crossing_inputs_keep_their_arithmetic(mean, true, apogee, expected):
|
||||
assert circular_chesta(mean, true, apogee) == expected
|
||||
@@ -0,0 +1,13 @@
|
||||
import pytest
|
||||
from scripts.shadbala import _ayana_bala
|
||||
|
||||
|
||||
@pytest.mark.parametrize("planet", ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"])
|
||||
def test_ayana_uses_wrapped_tropical_hemisphere(planet):
|
||||
assert _ayana_bala(planet, 350.0, 22.0) == _ayana_bala(planet, -10.0, 22.0)
|
||||
|
||||
|
||||
def test_venus_just_after_tropical_aries_uses_north_addition():
|
||||
bala, declination = _ayana_bala("Venus", 350.0, 22.0)
|
||||
assert declination > 0
|
||||
assert bala > 30
|
||||
@@ -0,0 +1,30 @@
|
||||
from datetime import date, timedelta
|
||||
import swisseph as swe
|
||||
import pytest
|
||||
from scripts.shadbala import _calendar_lords
|
||||
|
||||
|
||||
def context(day, hour):
|
||||
return {"year": day.year, "month": day.month, "day": day.day,
|
||||
"jd_local": swe.julday(day.year, day.month, day.day, hour),
|
||||
"local_hour": hour, "sunrise_hour": 6.0}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("offset,lord", enumerate(
|
||||
("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn")))
|
||||
def test_first_hora_is_weekday_lord(offset, lord):
|
||||
assert _calendar_lords(context(date(2026, 9, 27) + timedelta(days=offset), 6.1))["hora"] == lord
|
||||
|
||||
|
||||
def test_no_artificial_weekday_switch_at_julian_noon():
|
||||
# Saturday: seventh hour is Moon, eighth Saturn, ninth Jupiter.
|
||||
day = date(1993, 4, 17)
|
||||
assert _calendar_lords(context(day, 12.0))["hora"] == "Moon"
|
||||
assert _calendar_lords(context(day, 12.01))["hora"] == "Moon"
|
||||
assert _calendar_lords(context(day, 13.01))["hora"] == "Saturn"
|
||||
assert _calendar_lords(context(day, 14.01))["hora"] == "Jupiter"
|
||||
|
||||
|
||||
def test_before_sunrise_uses_previous_weekday():
|
||||
# Sunday 05:30 remains Saturday's 24th hora (Mars).
|
||||
assert _calendar_lords(context(date(2026, 9, 27), 5.5))["hora"] == "Mars"
|
||||
@@ -0,0 +1,30 @@
|
||||
import pytest
|
||||
|
||||
from scripts.shadbala import _surya_mean_longitude, _SURYA_REVOLUTIONS, _SURYA_CIVIL_DAYS
|
||||
|
||||
|
||||
@pytest.mark.parametrize("planet", list(_SURYA_REVOLUTIONS))
|
||||
@pytest.mark.parametrize("start", [2451544.49999, 2451544.99999, 2451545.1, 2451546.1,
|
||||
2451547.1, 2451548.1, 2451549.1, 2451550.1, 2451551.1])
|
||||
def test_mean_motion_has_no_noon_midnight_or_weekday_jumps(planet, start):
|
||||
rate = round(_SURYA_REVOLUTIONS[planet] / _SURYA_CIVIL_DAYS * 360, 7)
|
||||
for interval in (1 / 86400, 1.0, 7.0):
|
||||
a = _surya_mean_longitude(planet, {"jd_ut": start})
|
||||
b = _surya_mean_longitude(planet, {"jd_ut": start + interval})
|
||||
delta = (b - a + 180) % 360 - 180
|
||||
assert delta == pytest.approx(rate * interval, abs=1e-8)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("planet", list(_SURYA_REVOLUTIONS))
|
||||
def test_same_instant_has_one_mean_independent_of_clock_and_location(planet):
|
||||
instant = 2451545.0
|
||||
expected = _surya_mean_longitude(planet, {"jd_ut": instant})
|
||||
for timezone, longitude in [(0, 0), (5.5, 77.5), (8, 120), (-8, -122.4)]:
|
||||
context = {"jd_local": instant + timezone / 24,
|
||||
"timezone": timezone, "lon": longitude}
|
||||
assert _surya_mean_longitude(planet, context) == pytest.approx(expected, abs=1e-8)
|
||||
|
||||
|
||||
def test_ambiguous_civil_clock_without_offset_is_rejected():
|
||||
with pytest.raises(KeyError, match="timezone"):
|
||||
_surya_mean_longitude("Mercury", {"jd_local": 2451545.0, "lon": 120})
|
||||
@@ -59,13 +59,18 @@ def test_precise_sthana_bala_matches_pyjhora_same_chart() -> None:
|
||||
assert calc_sthana_bala_precise(planet, planets, houses[planet])["total"] == expected
|
||||
|
||||
|
||||
def test_precise_kala_bala_matches_pyjhora_same_chart() -> None:
|
||||
def test_precise_kala_preserves_archived_comparison_with_corrected_hora() -> None:
|
||||
# 原值: 每颗星 Kala 总分 == 存档 PyJHora 值(test_precise_kala_bala_matches_pyjhora_same_chart)
|
||||
# 新值: 月亮 +52.18、金星 −60.0,其余仍等于存档值(同上游 yinduzhanxing 0afa2780 的改法)
|
||||
# 原因: TASK-upstream-sync4-20261002 T3:时主按民用星期查 _HORA_ORDER(周四此时为月亮时),
|
||||
# Ayana 南北按取模后的回归黄经判断;存档 PyJHora 值只作对照,不作本地公式的标准答案
|
||||
planets = _planets()
|
||||
context = build_shadbala_context(2435163.6354166665, 37.7749, -122.4194, "lahiri", -8.0)
|
||||
assert abs(context["sunrise_hour"] - 6.886306) < 0.00001
|
||||
assert abs(context["sunset_hour"] - 17.890427) < 0.00001
|
||||
for planet, expected in PYJHORA_KALA.items():
|
||||
assert calc_kala_bala_precise(planet, planets, context)["total"] == expected
|
||||
delta = 52.18 if planet == "Moon" else -60.0 if planet == "Venus" else 0.0
|
||||
assert abs(calc_kala_bala_precise(planet, planets, context)["total"] - expected - delta) < 0.001
|
||||
|
||||
|
||||
def test_precise_chesta_uses_classical_bounded_variant() -> None:
|
||||
|
||||
Reference in New Issue
Block a user