Files
Jyotisha/scripts/annual_native/patyayini.py
T

97 lines
3.3 KiB
Python

"""Native Patyayini from an annual Lagna and the seven classical planets.
Durations follow the degree-within-sign arcs. The longitudes passed in are
not recomputed here.
"""
from __future__ import annotations
from datetime import datetime, timedelta
from typing import Any
SIGNS = (
"Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces",
)
_TIE = ("Jupiter", "Moon", "Mercury", "Saturn", "Lagna", "Sun", "Mars", "Venus")
def build_native_patyayini(
*,
ascendant_longitude: float,
planet_longitudes: dict[str, float],
start: datetime,
year_days: float = 365.25,
) -> dict[str, Any]:
points = {"Lagna": float(ascendant_longitude) % 360.0}
missing = []
for lord in ("Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"):
value = planet_longitudes.get(lord)
if isinstance(value, (int, float)) and not isinstance(value, bool):
points[lord] = float(value) % 360.0
else:
missing.append(lord)
if missing:
raise ValueError("patyayini missing longitudes: " + ", ".join(missing))
ordered = sorted(
(
{
"lord": lord,
"longitude": longitude,
"sign": SIGNS[int(longitude // 30) % 12],
"degree_in_sign": longitude % 30.0,
}
for lord, longitude in points.items()
),
key=lambda item: (item["degree_in_sign"], _TIE.index(item["lord"])),
)
denominator = ordered[-1]["degree_in_sign"]
if denominator <= 0.0:
raise ValueError("patyayini denominator is zero")
arcs = []
previous = 0.0
for item in ordered:
arc = max(0.0, float(item["degree_in_sign"]) - previous)
arcs.append(arc)
previous = float(item["degree_in_sign"])
periods = []
antardasha = []
cursor = start
for index, (item, arc) in enumerate(zip(ordered, arcs), start=1):
end = cursor + timedelta(days=float(year_days) * arc / denominator)
periods.append({
**item,
"order": index,
"start": _format(cursor),
"end": _format(end),
})
sub_cursor = cursor
cycle = ordered[index - 1:] + ordered[:index - 1]
cycle_arcs = arcs[index - 1:] + arcs[:index - 1]
main_seconds = (end - cursor).total_seconds()
for sub_index, (sub_item, sub_arc) in enumerate(zip(cycle, cycle_arcs), start=1):
sub_end = sub_cursor + timedelta(seconds=main_seconds * sub_arc / denominator)
antardasha.append({
"main": item["lord"],
"sub": sub_item["lord"],
"main_order": index,
"sub_order": sub_index,
"start": _format(sub_cursor),
"end": _format(sub_end),
"boundary": _format(sub_end),
"boundary_status": "dasha_ending_dates",
})
sub_cursor = sub_end
cursor = end
return {
"schema": "jyotish.patyayini_patyamsha_dasha.v1",
"status": "parameter_sensitive",
"model": "degree_within_sign",
"periods": periods,
"antardasha_periods": antardasha,
}
def _format(value: datetime) -> str:
return value.strftime("%Y-%m-%d %H:%M:%S")