Files
732642856 f83db2fac1 Enhance Jyotish validation and Jaimini modules
- add external validation reports and open-source comparison references

- integrate Jaimini arudha/graha pada, enhanced argala, and additional synastry kutas

- update skill docs and capability matrices

- add smoke tests for open-source integrations
2026-06-10 20:50:52 +08:00

98 lines
3.1 KiB
Python

import math
from .constants import TITHI_NAMES, VARA_NAMES, VARA_LORDS, PANCHANG_YOGA_NAMES, KARANA_NAMES
from .nakshatra import get_nakshatra
def calculate_panchang(jd, sun_lon, moon_lon, lat=None, lon=None):
"""
Calculate the five Panchang elements for a given moment.
Parameters
----------
jd : float
Julian Day number
sun_lon : float
Sidereal longitude of the Sun (0-360)
moon_lon : float
Sidereal longitude of the Moon (0-360)
Returns
-------
dict with tithi, vara, nakshatra, yoga, karana
"""
# --- Tithi ---
diff = (moon_lon - sun_lon) % 360.0
tithi_num = int(diff / 12.0) # 0-29
paksha = "Shukla" if tithi_num < 15 else "Krishna"
tithi_name = TITHI_NAMES[tithi_num]
# --- Vara (weekday) ---
# Julian Day 0 = Monday in many conventions; swe.julday for J2000 epoch
# JD 2451545.0 (2000-01-01 12:00 UT) was a Saturday
# weekday = (JD + 1.5) % 7 => 0=Mon, 1=Tue, ... 6=Sun (Julian convention)
day_idx = int(math.floor(jd + 0.5)) % 7
# Correct for local sunrise if lat/lon provided
if lat is not None and lon is not None:
try:
import swisseph as swe
swe.set_topo(lon, lat, 0)
# Find the sunrise for the current civil day UT
jd_midnight = math.floor(jd - 0.5) + 0.5
res, tret = swe.rise_trans(jd_midnight, swe.SUN, "", swe.CALC_RISE, (lon, lat, 0.0))
sunrise_jd = tret[0]
# If born before today's sunrise, the Vedic day is yesterday
if jd < sunrise_jd:
day_idx = (day_idx - 1) % 7
except Exception:
pass
# JD 0 = Monday (Julian proleptic). Map: 0=Mon,1=Tue,...6=Sun
vara = VARA_NAMES[day_idx]
vara_lord = VARA_LORDS[day_idx]
# --- Nakshatra (Moon's) ---
nak = get_nakshatra(moon_lon)
# --- Yoga (Panchang Yoga) ---
yoga_val = (sun_lon + moon_lon) % 360.0
yoga_idx = int(yoga_val / (360.0 / 27.0))
if yoga_idx >= 27:
yoga_idx = 26
yoga_name = PANCHANG_YOGA_NAMES[yoga_idx]
# --- Karana ---
# Each tithi has 2 karanas (half-tithi = 6 degrees of Sun-Moon distance)
karana_num = int(diff / 6.0) # 0-59
if karana_num == 0:
karana_name = KARANA_NAMES[10] # Kimstughna (first half of Shukla Pratipada)
elif karana_num >= 57:
# Last 3 are fixed karanas: Shakuni(57), Chatushpada(58), Nagava(59)
fixed_idx = karana_num - 57 + 7 # maps to indices 7,8,9
karana_name = KARANA_NAMES[fixed_idx]
else:
# Repeating cycle of first 7 karanas (Bava through Vishti)
karana_name = KARANA_NAMES[(karana_num - 1) % 7]
return {
"tithi": {
"number": tithi_num + 1,
"name": tithi_name,
"paksha": paksha,
},
"vara": {
"name": vara,
"lord": vara_lord,
},
"nakshatra": {
"name": nak["name"],
"pada": nak["pada"],
"lord": nak["lord"],
},
"yoga": {
"index": yoga_idx,
"name": yoga_name,
},
"karana": karana_name,
}