fix(tithi): use the source lord order (BUG-1473, upstream 33537b31)

Tithi lords follow tithi_seed. No new scripts/tithi_ashtottari.py. Upstream source tests passed.

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-28 09:45:06 +08:00
co-authored by Grok (agent loop)
parent d226b0e538
commit 9d3f59a872
2 changed files with 57 additions and 11 deletions
+23 -11
View File
@@ -8,6 +8,14 @@ Tithi(月日)是月亮与太阳的黄经差除以12°,共30个 Tithi(阴
import math
if __package__:
from .research_timing.cycles import tithi_seed
else:
try:
from research_timing.cycles import tithi_seed
except ImportError:
from scripts.research_timing.cycles import tithi_seed
# Tithi 名称(1-15 Shukla 盈,1-15 Krishna 亏)
TITHI_NAMES = {
1: "Pratipad (1)", 2: "Dvitiya (2)", 3: "Tritiya (3)", 4: "Chaturthi (4)",
@@ -16,15 +24,12 @@ TITHI_NAMES = {
13: "Trayodashi (13)", 14: "Chaturdashi (14)", 15: "Purnima/Amavasya (15)",
}
# Tithi 守护星(Parashara 系统)
# 1=Sun, 2=Moon, 3=Mars, 4=Mercury, 5=Jupiter, 6=Venus, 7=Saturn
# Tithi 1-7: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn
# Tithi 8-14: Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn
# Tithi 15 (Purnima/Amavasya): Sun
# PVR Integrated Approach table 3: Shukla mapping. Krishna 15 is Rahu,
# not Saturn; get_tithi_lord shares the existing thirty-day tithi_seed rule.
TITHI_LORD_MAP = {
1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6,
8: 0, 9: 1, 10: 2, 11: 3, 12: 4, 13: 5, 14: 6,
15: 0,
8: 7, 9: 0, 10: 1, 11: 2, 12: 3, 13: 4, 14: 5,
15: 6,
}
# 逆映射:行星索引 → 名称
@@ -62,11 +67,14 @@ def calc_tithi(sun_deg, moon_deg):
def get_tithi_lord(tithi_num, paksha):
"""
获取 Tithi 的守护星。
Tithi 1-15 的守护星在阴阳月中是一样的(Parashara 系统)。
PVR table 3;满月土星,新月罗睺,其余阴阳月对应一致。
"""
# Tithi 1-15 的守护星(阴阳月相同)
lord_idx = TITHI_LORD_MAP[tithi_num]
return lord_idx, PLANET_NAMES[lord_idx]
if type(tithi_num) is not int or not 1 <= tithi_num <= 15:
raise ValueError('tithi_num must be integer 1..15 within the paksha')
if paksha not in ('Shukla', 'Krishna'):
raise ValueError('paksha must be Shukla or Krishna')
name = tithi_seed(tithi_num + (15 if paksha == 'Krishna' else 0))
return PLANET_NAMES.index(name), name
def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None):
@@ -122,6 +130,8 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None):
15: 'Purnima(满月/新月,能量极点)',
}
special_note = special_tithis.get(tithi_num)
if tithi_num == 15:
special_note = 'Purnima(满月)' if paksha == 'Shukla' else 'Amavasya(新月)'
# Tithi 适忌活动表(完整版)
tithi_activities = _get_tithi_activities(tithi_num, paksha)
@@ -140,6 +150,7 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None):
"tithi_deg_in": round(tithi_deg, 2),
"tithi_lord_idx": lord_idx,
"tithi_lord_name": lord_name,
"tithi_lord_source": "PVR Integrated Approach table 3, file page 24; shared thirty-tithi ruler table",
"raw_diff_deg": round(raw_diff, 2),
# v7.0 新增
"tithi_class": tithi_class,
@@ -181,6 +192,7 @@ def calc_tithi_lord_full(sun_deg, moon_deg, planets=None, houses=None):
4: "Tithi Lord 为木星:智慧、导师、扩张、幸运。木星强则有人生指引。",
5: "Tithi Lord 为金星:享乐、艺术、关系、舒适。金星强则生活有质量。",
6: "Tithi Lord 为土星:纪律、延迟、责任、苦行。土星强则能承受压力。",
7: "Tithi Lord 为罗睺(PVR Table 3);应结合罗睺的本命位置与关联星综合判断。",
}
result["tithi_lord_interpretation"] = interpretations.get(lord_idx, "")
@@ -0,0 +1,34 @@
import pytest
from scripts.tithi_lord import calc_tithi_lord_full, get_tithi_lord
# PVR table 3, file p24. Independent explicit source expectation.
EXPECTED = ('Sun Moon Mars Mercury Jupiter Venus Saturn Rahu Sun Moon Mars Mercury Jupiter Venus Saturn '
'Sun Moon Mars Mercury Jupiter Venus Saturn Rahu Sun Moon Mars Mercury Jupiter Venus Rahu').split()
@pytest.mark.parametrize('number,lord',list(enumerate(EXPECTED,1)))
def test_all_thirty_report_rulers_and_angular_boundaries(number,lord):
at_start=calc_tithi_lord_full(0,(number-1)*12)
just_before_end=calc_tithi_lord_full(0,number*12-1e-7)
for result in (at_start,just_before_end):
assert result['tithi_absolute']==number
assert result['tithi_lord_name']==lord
def test_new_and_full_moon_differ_and_chart_link_follows_correct_lord():
full=calc_tithi_lord_full(0,174)
new=calc_tithi_lord_full(0,354,{'Rahu':{'sign':'Taurus','house':2}}, {})
assert full['tithi_lord_name']=='Saturn'
assert new['tithi_lord_name']=='Rahu'
assert full['special_note'] != new['special_note']
assert new['tithi_lord_sign']=='Taurus'
assert new['tithi_lord_house']==2
assert new['tithi_lord_interpretation']
assert calc_tithi_lord_full(0,360)['tithi_absolute']==1
@pytest.mark.parametrize('number,paksha',[(True,'Shukla'),(0,'Shukla'),(16,'Krishna'),(1,'unknown')])
def test_invalid_seed_is_not_silently_accepted(number,paksha):
with pytest.raises(ValueError):get_tithi_lord(number,paksha)