"""Ayanamsa (sidereal offset) definitions and registry for Stellium.
This module provides the ZodiacType enum and a registry of ayanamsa systems
used in sidereal astrology. Each ayanamsa represents a different calculation
method for determining the offset between the tropical and sidereal zodiacs.
"""
from dataclasses import dataclass
from enum import Enum
import swisseph as swe
[docs]
class ZodiacType(Enum):
"""Type of zodiac system used for calculations.
TROPICAL: Based on the seasons (0° Aries = March equinox)
SIDEREAL: Based on fixed star positions (varies by ayanamsa)
"""
TROPICAL = "tropical"
SIDEREAL = "sidereal"
[docs]
@dataclass(frozen=True)
class AyanamsaInfo:
"""Information about a specific ayanamsa system.
Attributes:
name: Human-readable name of the ayanamsa
swe_constant: Swiss Ephemeris constant for this ayanamsa
description: Brief description of the system
tradition: Tradition this ayanamsa belongs to (vedic, western_sidereal, etc.)
"""
name: str
swe_constant: int
description: str
tradition: str
# Registry of supported ayanamsa systems
# Key is lowercase name with underscores (for lookup)
AYANAMSA_REGISTRY: dict[str, AyanamsaInfo] = {
"lahiri": AyanamsaInfo(
name="Lahiri",
swe_constant=swe.SIDM_LAHIRI,
description="Indian government standard, Chitrapaksha ayanamsa",
tradition="vedic",
),
"fagan_bradley": AyanamsaInfo(
name="Fagan-Bradley",
swe_constant=swe.SIDM_FAGAN_BRADLEY,
description="Primary Western sidereal ayanamsa",
tradition="western_sidereal",
),
"raman": AyanamsaInfo(
name="Raman",
swe_constant=swe.SIDM_RAMAN,
description="B.V. Raman's ayanamsa, popular in South India",
tradition="vedic",
),
"krishnamurti": AyanamsaInfo(
name="Krishnamurti",
swe_constant=swe.SIDM_KRISHNAMURTI,
description="Used in KP (Krishnamurti Paddhati) system",
tradition="vedic",
),
"yukteshwar": AyanamsaInfo(
name="Yukteshwar",
swe_constant=swe.SIDM_YUKTESHWAR,
description="Sri Yukteshwar's ayanamsa from The Holy Science",
tradition="vedic",
),
"jn_bhasin": AyanamsaInfo(
name="J.N. Bhasin",
swe_constant=swe.SIDM_JN_BHASIN,
description="J.N. Bhasin's ayanamsa, North Indian variant",
tradition="vedic",
),
"true_citra": AyanamsaInfo(
name="True Chitrapaksha",
swe_constant=swe.SIDM_TRUE_CITRA,
description="Spica (Chitra) at exactly 0° Libra",
tradition="vedic",
),
"true_revati": AyanamsaInfo(
name="True Revati",
swe_constant=swe.SIDM_TRUE_REVATI,
description="Revati at exactly 0° Aries",
tradition="vedic",
),
"deluce": AyanamsaInfo(
name="De Luce",
swe_constant=swe.SIDM_DELUCE,
description="De Luce's Western sidereal ayanamsa",
tradition="western_sidereal",
),
}
[docs]
def get_ayanamsa(name: str) -> AyanamsaInfo:
"""Get ayanamsa information by name.
Args:
name: Name of the ayanamsa (case-insensitive, accepts spaces/hyphens)
Returns:
AyanamsaInfo for the requested ayanamsa
Raises:
ValueError: If ayanamsa name is not recognized
Examples:
>>> info = get_ayanamsa("lahiri")
>>> info.name
'Lahiri'
>>> info = get_ayanamsa("Fagan-Bradley") # Case insensitive, hyphen ok
>>> info.tradition
'western_sidereal'
"""
# Normalize name to lowercase with underscores
key = name.lower().replace("-", "_").replace(" ", "_")
if key not in AYANAMSA_REGISTRY:
available = ", ".join(sorted(AYANAMSA_REGISTRY.keys()))
raise ValueError(f"Unknown ayanamsa '{name}'. Available options: {available}")
return AYANAMSA_REGISTRY[key]
[docs]
def get_ayanamsa_value(julian_day: float, ayanamsa: str) -> float:
"""Calculate the ayanamsa offset value for a specific date.
The ayanamsa value represents the difference in degrees between the
tropical and sidereal zodiacs at a given point in time.
Args:
julian_day: Julian day number for the calculation
ayanamsa: Name of the ayanamsa system to use
Returns:
Ayanamsa offset in degrees
Example:
>>> from stellium.utils.time import datetime_to_julian_day
>>> from datetime import datetime
>>> jd = datetime_to_julian_day(datetime(2000, 1, 1, 12, 0))
>>> offset = get_ayanamsa_value(jd, "lahiri")
>>> print(f"Lahiri ayanamsa in 2000: {offset:.2f}°")
Lahiri ayanamsa in 2000: 23.85°
"""
ayanamsa_info = get_ayanamsa(ayanamsa)
swe.set_sid_mode(ayanamsa_info.swe_constant)
return swe.get_ayanamsa_ut(julian_day)
[docs]
def list_ayanamsas() -> list[str]:
"""Get a list of all available ayanamsa names.
Returns:
Sorted list of ayanamsa names (registry keys)
Example:
>>> available = list_ayanamsas()
>>> "lahiri" in available
True
>>> "fagan_bradley" in available
True
"""
return sorted(AYANAMSA_REGISTRY.keys())