libaditya 0.3.4__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libaditya/__init__.py +46 -0
- libaditya/_version.py +29 -0
- libaditya/calc/__init__.py +9 -0
- libaditya/calc/api.py +30 -0
- libaditya/calc/avasthas.py +346 -0
- libaditya/calc/docs/jaimini-get-arch.md +95 -0
- libaditya/calc/hellenistic.py +37 -0
- libaditya/calc/jaimini.py +335 -0
- libaditya/calc/jaimini_get.py +240 -0
- libaditya/calc/kala.py +73 -0
- libaditya/calc/panchanga.py +422 -0
- libaditya/calc/rashi.py +612 -0
- libaditya/calc/returns.py +50 -0
- libaditya/calc/swe_functions.py +118 -0
- libaditya/calc/varga.py +287 -0
- libaditya/calc/vimshottari.py +431 -0
- libaditya/cards/__init__.py +5 -0
- libaditya/cards/card.py +90 -0
- libaditya/cards/cards_constants.py +115 -0
- libaditya/cards/cards_of_truth.py +323 -0
- libaditya/cards/cot.py +142 -0
- libaditya/cards/deck.py +52 -0
- libaditya/charts/__init__.py +6 -0
- libaditya/charts/api.py +36 -0
- libaditya/charts/bodygraph.py +80 -0
- libaditya/charts/chart.py +286 -0
- libaditya/charts/jaimini.py +83 -0
- libaditya/charts/tajika.py +36 -0
- libaditya/constants.py +1776 -0
- libaditya/draw/__init__.py +20 -0
- libaditya/draw/draw_bodygraph.py +489 -0
- libaditya/draw/draw_sbc.py +712 -0
- libaditya/draw/themes/default-theme.hd +53 -0
- libaditya/ephe/ast0/se00010s.se1 +0 -0
- libaditya/ephe/seas_00.se1 +0 -0
- libaditya/ephe/seas_06.se1 +0 -0
- libaditya/ephe/seas_12.se1 +0 -0
- libaditya/ephe/seas_18.se1 +0 -0
- libaditya/ephe/seas_24.se1 +0 -0
- libaditya/ephe/seas_30.se1 +0 -0
- libaditya/ephe/seas_36.se1 +0 -0
- libaditya/ephe/seas_42.se1 +0 -0
- libaditya/ephe/seas_48.se1 +0 -0
- libaditya/ephe/seasm06.se1 +0 -0
- libaditya/ephe/seasm12.se1 +0 -0
- libaditya/ephe/seasm18.se1 +0 -0
- libaditya/ephe/seasm24.se1 +0 -0
- libaditya/ephe/seasm30.se1 +0 -0
- libaditya/ephe/seasm36.se1 +0 -0
- libaditya/ephe/seasm42.se1 +0 -0
- libaditya/ephe/seasm48.se1 +0 -0
- libaditya/ephe/seasm54.se1 +0 -0
- libaditya/ephe/sefstars.txt +4245 -0
- libaditya/ephe/semo_00.se1 +0 -0
- libaditya/ephe/semo_06.se1 +0 -0
- libaditya/ephe/semo_12.se1 +0 -0
- libaditya/ephe/semo_18.se1 +0 -0
- libaditya/ephe/semo_24.se1 +0 -0
- libaditya/ephe/semo_30.se1 +0 -0
- libaditya/ephe/semo_36.se1 +0 -0
- libaditya/ephe/semo_42.se1 +0 -0
- libaditya/ephe/semo_48.se1 +0 -0
- libaditya/ephe/semom06.se1 +0 -0
- libaditya/ephe/semom12.se1 +0 -0
- libaditya/ephe/semom18.se1 +0 -0
- libaditya/ephe/semom24.se1 +0 -0
- libaditya/ephe/semom30.se1 +0 -0
- libaditya/ephe/semom36.se1 +0 -0
- libaditya/ephe/semom42.se1 +0 -0
- libaditya/ephe/semom48.se1 +0 -0
- libaditya/ephe/semom54.se1 +0 -0
- libaditya/ephe/sepl_00.se1 +0 -0
- libaditya/ephe/sepl_06.se1 +0 -0
- libaditya/ephe/sepl_12.se1 +0 -0
- libaditya/ephe/sepl_18.se1 +0 -0
- libaditya/ephe/sepl_24.se1 +0 -0
- libaditya/ephe/sepl_30.se1 +0 -0
- libaditya/ephe/sepl_36.se1 +0 -0
- libaditya/ephe/sepl_42.se1 +0 -0
- libaditya/ephe/sepl_48.se1 +0 -0
- libaditya/ephe/seplm06.se1 +0 -0
- libaditya/ephe/seplm12.se1 +0 -0
- libaditya/ephe/seplm18.se1 +0 -0
- libaditya/ephe/seplm24.se1 +0 -0
- libaditya/ephe/seplm30.se1 +0 -0
- libaditya/ephe/seplm36.se1 +0 -0
- libaditya/ephe/seplm42.se1 +0 -0
- libaditya/ephe/seplm48.se1 +0 -0
- libaditya/ephe/seplm54.se1 +0 -0
- libaditya/hd/__init__.py +8 -0
- libaditya/hd/calc.py +55 -0
- libaditya/hd/constants.py +127 -0
- libaditya/hd/longitude.py +271 -0
- libaditya/objects/__init__.py +19 -0
- libaditya/objects/celestial_object.py +206 -0
- libaditya/objects/context.py +133 -0
- libaditya/objects/cusps.py +259 -0
- libaditya/objects/julian_day.py +265 -0
- libaditya/objects/location.py +167 -0
- libaditya/objects/longitude.py +987 -0
- libaditya/objects/nakshatras.py +285 -0
- libaditya/objects/planets.py +2059 -0
- libaditya/objects/shadbala.py +398 -0
- libaditya/objects/signs.py +690 -0
- libaditya/objects/swe_functions.py +75 -0
- libaditya/print_functions.py +548 -0
- libaditya/read.py +665 -0
- libaditya/stars/__init__.py +4 -0
- libaditya/stars/fixed_star.py +216 -0
- libaditya/stars/make_swe_stars.py +407 -0
- libaditya/stars/star-sign-boundaries +44 -0
- libaditya/stars/stellarium/__init__.py +6 -0
- libaditya/stars/stellarium/remote_control/__init__.py +22 -0
- libaditya/stars/stellarium/remote_control/location.py +82 -0
- libaditya/stars/stellarium/remote_control/locationsearch.py +35 -0
- libaditya/stars/stellarium/remote_control/main.py +165 -0
- libaditya/stars/stellarium/remote_control/objects.py +63 -0
- libaditya/stars/stellarium/remote_control/scripts.py +81 -0
- libaditya/stars/stellarium/remote_control/simbad.py +20 -0
- libaditya/stars/stellarium/remote_control/stelaction.py +31 -0
- libaditya/stars/stellarium/remote_control/stelproperty.py +30 -0
- libaditya/stars/stellarium/remote_control/view.py +85 -0
- libaditya/stars/stellarium/stellarium.py +92 -0
- libaditya/stars/the_stars.py +522 -0
- libaditya/stars/utilities.py +539 -0
- libaditya/utils.py +431 -0
- libaditya/write.py +67 -0
- libaditya-0.3.4.dist-info/METADATA +588 -0
- libaditya-0.3.4.dist-info/RECORD +131 -0
- libaditya-0.3.4.dist-info/WHEEL +5 -0
- libaditya-0.3.4.dist-info/licenses/LICENSE +661 -0
libaditya/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# This file is part of libaditya.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
|
|
4
|
+
#
|
|
5
|
+
# libaditya is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# libaditya is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with libaditya. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import swisseph as swe
|
|
19
|
+
import pathlib
|
|
20
|
+
from dataclasses import replace
|
|
21
|
+
from rich.console import Console
|
|
22
|
+
|
|
23
|
+
from libaditya.objects import *
|
|
24
|
+
from libaditya.calc import *
|
|
25
|
+
from libaditya.charts import *
|
|
26
|
+
from libaditya.hd import *
|
|
27
|
+
from libaditya.stars import *
|
|
28
|
+
from libaditya.cards import *
|
|
29
|
+
from libaditya import constants as const
|
|
30
|
+
from libaditya import utils
|
|
31
|
+
from libaditya import read
|
|
32
|
+
from libaditya import write
|
|
33
|
+
from libaditya import print_functions as printf
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# base_path means for libaditya src itself
|
|
37
|
+
base_path = os.path.dirname(os.path.realpath(__file__))
|
|
38
|
+
# the
|
|
39
|
+
package_path = os.path.dirname(pathlib.Path(__file__).parent)+"/"
|
|
40
|
+
|
|
41
|
+
swe.set_ephe_path(base_path + "/ephe/")
|
|
42
|
+
|
|
43
|
+
console = Console()
|
|
44
|
+
|
|
45
|
+
# from ._version import __version__
|
|
46
|
+
|
libaditya/_version.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# This file is part of libaditya.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
|
|
4
|
+
#
|
|
5
|
+
# libaditya is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# libaditya is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with libaditya. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
# this sets __version__ for everyone
|
|
19
|
+
|
|
20
|
+
import toml
|
|
21
|
+
import os
|
|
22
|
+
import pathlib
|
|
23
|
+
|
|
24
|
+
package_path = os.path.dirname(pathlib.Path(__file__).parent)+"/"
|
|
25
|
+
|
|
26
|
+
with open(package_path+"pyproject.toml", 'r') as f:
|
|
27
|
+
config = toml.load(f)
|
|
28
|
+
|
|
29
|
+
__version__ = config["project"]["version"]
|
libaditya/calc/api.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# This file is part of libaditya.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
|
|
4
|
+
#
|
|
5
|
+
# libaditya is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# libaditya is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with libaditya. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
from libaditya.objects import Sign
|
|
19
|
+
|
|
20
|
+
class API:
|
|
21
|
+
"""
|
|
22
|
+
a Mixin API for Varga
|
|
23
|
+
these are just functions to help make finding information easier
|
|
24
|
+
these are all simply wrappers for other functions
|
|
25
|
+
e.g., rashi_aspects are computed by Signs, but there is a function in here
|
|
26
|
+
to access them from Varga
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def rashi_aspects_given_to(self, sign: Sign) -> [Sign]:
|
|
30
|
+
return self.signs().rashi_aspects_given_to(sign)
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# This file is part of libaditya.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
|
|
4
|
+
#
|
|
5
|
+
# libaditya is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# libaditya is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with libaditya. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
import math
|
|
19
|
+
import swisseph as swe
|
|
20
|
+
|
|
21
|
+
from libaditya import constants as const
|
|
22
|
+
from libaditya import utils
|
|
23
|
+
|
|
24
|
+
KARAKAS = ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
|
25
|
+
GRAHAS = KARAKAS + ["Rahu", "Ketu"]
|
|
26
|
+
WATER_SIGNS = {4, 8, 12}
|
|
27
|
+
|
|
28
|
+
BALADI_STATES = ["Bala", "Kumara", "Yuva", "Vriddha", "Mrita"]
|
|
29
|
+
JAGRADADI_STATES = ["Jagrat", "Swapna", "Sushupti"]
|
|
30
|
+
DEEPTADI_STATES = ["Deepta", "Swastha", "Mudita", "Shanta", "Shakta",
|
|
31
|
+
"Peedita", "Deena", "Vikala", "Khala"]
|
|
32
|
+
SHAYANADI_STATES = ["Shayana", "Upavesha", "Netrapani", "Prakasha",
|
|
33
|
+
"Gamana", "Agamana", "Sabha", "Agama",
|
|
34
|
+
"Bhojana", "Nrityalipsa", "Kautuka", "Nidra"]
|
|
35
|
+
SHAYANADI_MULTIPLIERS = {"Sun": 5, "Moon": 2, "Mars": 2, "Mercury": 3,
|
|
36
|
+
"Jupiter": 5, "Venus": 3, "Saturn": 3}
|
|
37
|
+
COMBUST_ORBS = {"Moon": 12, "Mars": 17, "Mercury": 14, "Jupiter": 11,
|
|
38
|
+
"Venus": 10, "Saturn": 15}
|
|
39
|
+
BENEFIC_NAVAMSA_SIGNS = {2, 3, 4, 6, 7, 9, 12}
|
|
40
|
+
NATURAL_MALEFICS = {"Sun", "Mars", "Saturn", "Rahu", "Ketu"}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LajjitaadiAvasthas:
|
|
44
|
+
|
|
45
|
+
def lajjitaadi_avasthas(self) -> dict:
|
|
46
|
+
"""
|
|
47
|
+
Calculate Lajjitaadi Avasthas for the seven karakas.
|
|
48
|
+
|
|
49
|
+
Returns a dict keyed by planet name, each value being a dict of
|
|
50
|
+
avastha names mapped to lists of contributing factors. Each factor
|
|
51
|
+
has a source, strength (0-60), and relevant planet/lord info.
|
|
52
|
+
|
|
53
|
+
Ernst Wilhelm's version plus custom Healthy (Svastha) avastha.
|
|
54
|
+
"""
|
|
55
|
+
planets = self.planets()
|
|
56
|
+
signs = self.signs()
|
|
57
|
+
cusps = self.cusps()
|
|
58
|
+
lagna = signs.lagna()
|
|
59
|
+
fifth_sign_num = lagna.astrological_signs_forward(5)
|
|
60
|
+
|
|
61
|
+
result = {}
|
|
62
|
+
|
|
63
|
+
for name in KARAKAS:
|
|
64
|
+
planet = planets[name]
|
|
65
|
+
avasthas = {}
|
|
66
|
+
sign_num = planet.sign()
|
|
67
|
+
sign_lord = const.lords[sign_num]
|
|
68
|
+
|
|
69
|
+
# precompute natural relationships and aspects from other planets
|
|
70
|
+
for other_name in GRAHAS:
|
|
71
|
+
if other_name == name:
|
|
72
|
+
continue
|
|
73
|
+
other = planets[other_name]
|
|
74
|
+
aspect = planet.parashara_aspect_from(other)
|
|
75
|
+
is_conjunction = (aspect == "Y")
|
|
76
|
+
aspect_strength = aspect if isinstance(aspect, (int, float)) else None
|
|
77
|
+
# natural relationship: how does planet feel about other?
|
|
78
|
+
if other_name in KARAKAS:
|
|
79
|
+
rel = planet.natural_relationship_from(other)
|
|
80
|
+
else:
|
|
81
|
+
rel = None
|
|
82
|
+
is_friend = rel in ("F", "OH")
|
|
83
|
+
is_enemy = rel == "E"
|
|
84
|
+
|
|
85
|
+
# --- Delighted ---
|
|
86
|
+
# conjunct Jupiter
|
|
87
|
+
if is_conjunction and other_name == "Jupiter":
|
|
88
|
+
_add(avasthas, "delighted", {"source": "conjunction", "planet": other_name, "strength": 60})
|
|
89
|
+
# conjunct natural friend (except Saturn)
|
|
90
|
+
if is_conjunction and is_friend and other_name != "Saturn":
|
|
91
|
+
_add(avasthas, "delighted", {"source": "conjunction", "planet": other_name, "strength": 60})
|
|
92
|
+
# aspected by natural friend
|
|
93
|
+
if aspect_strength and is_friend:
|
|
94
|
+
_add(avasthas, "delighted", {"source": "aspect", "planet": other_name, "strength": aspect_strength})
|
|
95
|
+
|
|
96
|
+
# --- Starved ---
|
|
97
|
+
# conjunct natural enemy
|
|
98
|
+
if is_conjunction and is_enemy:
|
|
99
|
+
_add(avasthas, "starved", {"source": "conjunction", "planet": other_name, "strength": 60})
|
|
100
|
+
# conjunct Saturn (for non-Saturn planets)
|
|
101
|
+
if is_conjunction and other_name == "Saturn":
|
|
102
|
+
_add(avasthas, "starved", {"source": "conjunction", "planet": "Saturn", "strength": 60})
|
|
103
|
+
# aspected by natural enemy
|
|
104
|
+
if aspect_strength and is_enemy:
|
|
105
|
+
_add(avasthas, "starved", {"source": "aspect", "planet": other_name, "strength": aspect_strength})
|
|
106
|
+
|
|
107
|
+
# --- Agitated ---
|
|
108
|
+
# conjunct Sun
|
|
109
|
+
if is_conjunction and other_name == "Sun":
|
|
110
|
+
_add(avasthas, "agitated", {"source": "conjunction", "planet": "Sun", "strength": 60})
|
|
111
|
+
# aspected by natural enemy who is also a natural malefic
|
|
112
|
+
if aspect_strength and is_enemy and other_name in KARAKAS:
|
|
113
|
+
if other.nature() == "Malefic":
|
|
114
|
+
_add(avasthas, "agitated", {"source": "aspect", "planet": other_name, "strength": aspect_strength})
|
|
115
|
+
|
|
116
|
+
# --- Thirsty ---
|
|
117
|
+
# in a water sign AND aspected by natural enemy
|
|
118
|
+
if sign_num in WATER_SIGNS and aspect_strength and is_enemy:
|
|
119
|
+
_add(avasthas, "thirsty", {"source": "aspect", "planet": other_name, "strength": aspect_strength})
|
|
120
|
+
|
|
121
|
+
# --- Delighted: in sign of natural friend ---
|
|
122
|
+
if sign_lord != name and sign_lord in KARAKAS:
|
|
123
|
+
lord_planet = planets[sign_lord]
|
|
124
|
+
rel_to_lord = planet.natural_relationship_from(lord_planet)
|
|
125
|
+
if rel_to_lord in ("F", "OH"):
|
|
126
|
+
_add(avasthas, "delighted", {"source": "sign", "lord": sign_lord, "strength": 60})
|
|
127
|
+
|
|
128
|
+
# --- Starved: in sign of natural enemy ---
|
|
129
|
+
if sign_lord != name and sign_lord in KARAKAS:
|
|
130
|
+
lord_planet = planets[sign_lord]
|
|
131
|
+
rel_to_lord = planet.natural_relationship_from(lord_planet)
|
|
132
|
+
if rel_to_lord == "E":
|
|
133
|
+
_add(avasthas, "starved", {"source": "sign", "lord": sign_lord, "strength": 60})
|
|
134
|
+
|
|
135
|
+
# --- Healthy: planet in own sign ---
|
|
136
|
+
if planet.is_oh():
|
|
137
|
+
_add(avasthas, "healthy", {"source": "sign", "strength": 60})
|
|
138
|
+
|
|
139
|
+
# --- Proud: planet is EX or MT ---
|
|
140
|
+
if planet.is_ex():
|
|
141
|
+
_add(avasthas, "proud", {"source": "dignity", "dignity": "EX", "strength": 60})
|
|
142
|
+
elif planet.is_mt():
|
|
143
|
+
_add(avasthas, "proud", {"source": "dignity", "dignity": "MT", "strength": 60})
|
|
144
|
+
|
|
145
|
+
# --- Thirsty: water sign check (base condition) ---
|
|
146
|
+
# already handled above in the per-other loop; the water sign is a
|
|
147
|
+
# prerequisite for the aspect trigger, not a standalone trigger
|
|
148
|
+
|
|
149
|
+
# --- Shamed ---
|
|
150
|
+
# conjunct Sun/Mars/Saturn AND (conjunct Rahu/Ketu OR in 5th sign OR conjunct 5th cusp)
|
|
151
|
+
conj_sun_mars_saturn = []
|
|
152
|
+
conj_rahu_ketu = False
|
|
153
|
+
for other_name in GRAHAS:
|
|
154
|
+
if other_name == name:
|
|
155
|
+
continue
|
|
156
|
+
other = planets[other_name]
|
|
157
|
+
aspect = planet.parashara_aspect_from(other)
|
|
158
|
+
if aspect == "Y":
|
|
159
|
+
if other_name in ("Sun", "Mars", "Saturn"):
|
|
160
|
+
conj_sun_mars_saturn.append(other_name)
|
|
161
|
+
if other_name in ("Rahu", "Ketu"):
|
|
162
|
+
conj_rahu_ketu = True
|
|
163
|
+
|
|
164
|
+
if conj_sun_mars_saturn:
|
|
165
|
+
in_fifth_sign = (sign_num == fifth_sign_num)
|
|
166
|
+
conj_fifth_cusp = (planet.sign() == cusps[5].sign())
|
|
167
|
+
if conj_rahu_ketu or in_fifth_sign or conj_fifth_cusp:
|
|
168
|
+
for trigger in conj_sun_mars_saturn:
|
|
169
|
+
_add(avasthas, "shamed", {"source": "conjunction", "planet": trigger, "strength": 60})
|
|
170
|
+
if conj_rahu_ketu:
|
|
171
|
+
_add(avasthas, "shamed", {"source": "condition", "detail": "conjunct Rahu/Ketu"})
|
|
172
|
+
if in_fifth_sign:
|
|
173
|
+
_add(avasthas, "shamed", {"source": "condition", "detail": "in 5th sign"})
|
|
174
|
+
if conj_fifth_cusp and not in_fifth_sign:
|
|
175
|
+
_add(avasthas, "shamed", {"source": "condition", "detail": "conjunct 5th cusp"})
|
|
176
|
+
|
|
177
|
+
planet.attributes["lajjitaadi_avasthas"] = avasthas
|
|
178
|
+
if avasthas:
|
|
179
|
+
result[name] = avasthas
|
|
180
|
+
sign_obj = signs[sign_num]
|
|
181
|
+
sign_obj._lajjitaadi_avasthas[name] = avasthas
|
|
182
|
+
|
|
183
|
+
# build giving and receiving dicts for each karaka
|
|
184
|
+
for name in KARAKAS:
|
|
185
|
+
planet = planets[name]
|
|
186
|
+
avasthas = planet.attributes["lajjitaadi_avasthas"]
|
|
187
|
+
# receiving: factors from my avasthas where another planet is the cause
|
|
188
|
+
receiving = {}
|
|
189
|
+
for avastha, factors in avasthas.items():
|
|
190
|
+
planet_factors = [f for f in factors if "planet" in f]
|
|
191
|
+
if planet_factors:
|
|
192
|
+
receiving[avastha] = planet_factors
|
|
193
|
+
planet.attributes["lajjitaadi_receiving"] = receiving
|
|
194
|
+
# giving: scan all other planets' avasthas for factors where I am the cause
|
|
195
|
+
giving = {}
|
|
196
|
+
for other_name in KARAKAS:
|
|
197
|
+
if other_name == name:
|
|
198
|
+
continue
|
|
199
|
+
other_avasthas = planets[other_name].attributes["lajjitaadi_avasthas"]
|
|
200
|
+
for avastha, factors in other_avasthas.items():
|
|
201
|
+
for f in factors:
|
|
202
|
+
if f.get("planet") == name:
|
|
203
|
+
_add(giving, avastha, {**f, "to": other_name})
|
|
204
|
+
planet.attributes["lajjitaadi_giving"] = giving
|
|
205
|
+
|
|
206
|
+
return result
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _add(avasthas, avastha_name, factor):
|
|
210
|
+
if avastha_name not in avasthas:
|
|
211
|
+
avasthas[avastha_name] = []
|
|
212
|
+
avasthas[avastha_name].append(factor)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class BaladiAvasthas:
|
|
216
|
+
|
|
217
|
+
def baladi_avasthas(self) -> dict:
|
|
218
|
+
planets = self.planets()
|
|
219
|
+
result = {}
|
|
220
|
+
for name in KARAKAS:
|
|
221
|
+
planet = planets[name]
|
|
222
|
+
degree = planet.real_in_sign_longitude()
|
|
223
|
+
b = math.floor(degree / 6.0)
|
|
224
|
+
if b > 4:
|
|
225
|
+
b = 4
|
|
226
|
+
if utils.even(planet.sign()):
|
|
227
|
+
b = 4 - b
|
|
228
|
+
state = BALADI_STATES[b]
|
|
229
|
+
planet.attributes["baladi_avastha"] = state
|
|
230
|
+
result[name] = state
|
|
231
|
+
return result
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
class JagradadiAvasthas:
|
|
235
|
+
|
|
236
|
+
def jagradadi_avasthas(self) -> dict:
|
|
237
|
+
planets = self.planets()
|
|
238
|
+
result = {}
|
|
239
|
+
for name in KARAKAS:
|
|
240
|
+
planet = planets[name]
|
|
241
|
+
if planet.is_ex() or planet.is_oh() or planet.is_mt():
|
|
242
|
+
state = "Jagrat"
|
|
243
|
+
elif planet.dignity() in ("F", "GF"):
|
|
244
|
+
state = "Swapna"
|
|
245
|
+
else:
|
|
246
|
+
state = "Sushupti"
|
|
247
|
+
planet.attributes["jagradadi_avastha"] = state
|
|
248
|
+
result[name] = state
|
|
249
|
+
return result
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
class DeeptadiAvasthas:
|
|
253
|
+
|
|
254
|
+
def deeptadi_avasthas(self) -> dict:
|
|
255
|
+
planets = self.planets()
|
|
256
|
+
sun = planets["Sun"]
|
|
257
|
+
result = {}
|
|
258
|
+
for name in KARAKAS:
|
|
259
|
+
planet = planets[name]
|
|
260
|
+
state = self._deeptadi_state(planet, name, planets, sun)
|
|
261
|
+
planet.attributes["deeptadi_avastha"] = state
|
|
262
|
+
result[name] = state
|
|
263
|
+
return result
|
|
264
|
+
|
|
265
|
+
def _deeptadi_state(self, planet, name, planets, sun):
|
|
266
|
+
# 1. Deepta - exalted
|
|
267
|
+
if planet.is_ex():
|
|
268
|
+
return "Deepta"
|
|
269
|
+
# 2. Swastha - own sign
|
|
270
|
+
if planet.is_oh():
|
|
271
|
+
return "Swastha"
|
|
272
|
+
# 3. Mudita - friend's sign
|
|
273
|
+
if planet.dignity() in ("F", "GF"):
|
|
274
|
+
return "Mudita"
|
|
275
|
+
# 4. Shanta - benefic navamsa sign
|
|
276
|
+
navamsa_sign = math.floor(planet.ecliptic_longitude() / (30 / 9)) % 12 + 1
|
|
277
|
+
if navamsa_sign in BENEFIC_NAVAMSA_SIGNS:
|
|
278
|
+
return "Shanta"
|
|
279
|
+
# 5. Shakta - retrograde
|
|
280
|
+
if planet.retrograde():
|
|
281
|
+
return "Shakta"
|
|
282
|
+
# 6. Peedita - conjunct a natural malefic
|
|
283
|
+
for other_name in GRAHAS:
|
|
284
|
+
if other_name == name:
|
|
285
|
+
continue
|
|
286
|
+
if other_name not in NATURAL_MALEFICS:
|
|
287
|
+
continue
|
|
288
|
+
other = planets[other_name]
|
|
289
|
+
aspect = planet.parashara_aspect_from(other)
|
|
290
|
+
if aspect == "Y":
|
|
291
|
+
return "Peedita"
|
|
292
|
+
# 7. Deena - debilitated
|
|
293
|
+
if planet.is_db():
|
|
294
|
+
return "Deena"
|
|
295
|
+
# 8. Vikala - combust
|
|
296
|
+
if name != "Sun" and name in COMBUST_ORBS:
|
|
297
|
+
sep = abs(planet.ecliptic_longitude() - sun.ecliptic_longitude())
|
|
298
|
+
if sep > 180:
|
|
299
|
+
sep = 360 - sep
|
|
300
|
+
orb = COMBUST_ORBS[name]
|
|
301
|
+
if name == "Mercury" and planet.retrograde():
|
|
302
|
+
orb = 12
|
|
303
|
+
if sep <= orb:
|
|
304
|
+
return "Vikala"
|
|
305
|
+
# 9. Khala - enemy's sign
|
|
306
|
+
if planet.dignity() in ("E", "GE"):
|
|
307
|
+
return "Khala"
|
|
308
|
+
# fallback (shouldn't normally happen - neutral sign, not retro, not combust, etc.)
|
|
309
|
+
return "Shanta"
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class ShayanadiAvasthas:
|
|
313
|
+
|
|
314
|
+
def shayanadi_avasthas(self) -> dict:
|
|
315
|
+
planets = self.planets()
|
|
316
|
+
context = self.context
|
|
317
|
+
birth_jd = context.timeJD.jd_number()
|
|
318
|
+
# find the most recent sunrise before birth
|
|
319
|
+
# rise_trans finds the *next* rise, so start from ~1 day before birth
|
|
320
|
+
sunrise_jd = swe.rise_trans(
|
|
321
|
+
birth_jd - 1,
|
|
322
|
+
swe.SUN,
|
|
323
|
+
swe.CALC_RISE | swe.BIT_HINDU_RISING,
|
|
324
|
+
context.location.swe_location(),
|
|
325
|
+
)[1][0]
|
|
326
|
+
# if that sunrise is still after birth (shouldn't happen), go back further
|
|
327
|
+
if sunrise_jd > birth_jd:
|
|
328
|
+
sunrise_jd = swe.rise_trans(
|
|
329
|
+
birth_jd - 2,
|
|
330
|
+
swe.SUN,
|
|
331
|
+
swe.CALC_RISE | swe.BIT_HINDU_RISING,
|
|
332
|
+
context.location.swe_location(),
|
|
333
|
+
)[1][0]
|
|
334
|
+
birth_ghatis = (birth_jd - sunrise_jd) * 60
|
|
335
|
+
|
|
336
|
+
result = {}
|
|
337
|
+
for name in KARAKAS:
|
|
338
|
+
planet = planets[name]
|
|
339
|
+
nak_num = planet.nakshatra().index() + 1
|
|
340
|
+
multiplier = SHAYANADI_MULTIPLIERS[name]
|
|
341
|
+
navamsa_num = math.floor(planet.real_in_sign_longitude() / (30 / 9)) + 1
|
|
342
|
+
value = math.floor(nak_num * multiplier + navamsa_num + birth_ghatis) % 12
|
|
343
|
+
state = SHAYANADI_STATES[value]
|
|
344
|
+
planet.attributes["shayanadi_avastha"] = state
|
|
345
|
+
result[name] = state
|
|
346
|
+
return result
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# jaimini_get.py — Architecture
|
|
2
|
+
|
|
3
|
+
## What this does
|
|
4
|
+
|
|
5
|
+
In Jaimini astrology, interpretation often starts from a specific sign — usually derived from a karaka (significator) placement — and then asks: **what planets influence that sign?** Influence means conjunction (planets in the sign) and rashi aspects (planets in signs that aspect it).
|
|
6
|
+
|
|
7
|
+
The question varies by topic:
|
|
8
|
+
|
|
9
|
+
- **Spirituality**: what influences the 12th sign from the Atmakaraka?
|
|
10
|
+
- **Spouse**: what influences the 7th sign from the Atmakaraka?
|
|
11
|
+
- **Home**: what influences the 4th sign from the Atmakaraka?
|
|
12
|
+
- **Karakamshas**: what influences the sign the Atmakaraka itself sits in?
|
|
13
|
+
- **Farmer**: what influences the 3rd, 6th, and 9th house cusps?
|
|
14
|
+
|
|
15
|
+
Each of these is the same operation with different inputs. `jaimini_get.py` encodes those inputs declaratively and provides one general method to compute them all.
|
|
16
|
+
|
|
17
|
+
## Gets: the declarative specs
|
|
18
|
+
|
|
19
|
+
The `Gets` class holds topic definitions as class-level dicts. Each has two keys:
|
|
20
|
+
|
|
21
|
+
- **`factor`**: a list of strings identifying which sign(s) to examine
|
|
22
|
+
- **`vargas`**: a list of divisional chart numbers to check, in priority order
|
|
23
|
+
|
|
24
|
+
### Factor string format
|
|
25
|
+
|
|
26
|
+
Three shapes:
|
|
27
|
+
|
|
28
|
+
| Format | Example | Meaning |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| `"N away XK"` | `"12 away AK"` | Count N signs from karaka XK. Direction depends on odd/even: odd sign = forward, even sign = backward. |
|
|
31
|
+
| `"XK"` | `"AK"` | The sign the karaka occupies (no counting). |
|
|
32
|
+
| `"N"` | `"3"` | The sign of the Nth house cusp (no karaka involved). |
|
|
33
|
+
|
|
34
|
+
Karaka abbreviations map to `jaimini_karakas()` return order:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
0: AK (Atmakaraka)
|
|
38
|
+
1: AmK (Amatyakaraka)
|
|
39
|
+
2: BK (Bhratrukaraka)
|
|
40
|
+
3: MK (Matrukaraka / Putrakaraka)
|
|
41
|
+
4: PiK (Pitrkaraka)
|
|
42
|
+
5: GK (Gnatikaraka)
|
|
43
|
+
6: DK (Darakaraka)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Varga overrides
|
|
47
|
+
|
|
48
|
+
Some vargas have variants. The D24 (Chaturvimsamsha) has a standard version and the Siddhamsha (`-240`), where even signs start from Cancer in reverse. The `get()` method accepts `varga_overrides` to swap variants. Default: `{"24": "-240"}`.
|
|
49
|
+
|
|
50
|
+
## JaiminiGet.get(): the general method
|
|
51
|
+
|
|
52
|
+
`get(spec, varga_overrides=None)` does the following:
|
|
53
|
+
|
|
54
|
+
1. Resolves varga numbers through overrides
|
|
55
|
+
2. Gets the jaimini karaka list once
|
|
56
|
+
3. For each factor in the spec:
|
|
57
|
+
- For each varga:
|
|
58
|
+
- Finds the target sign (karaka placement + offset with direction, or cusp sign)
|
|
59
|
+
- Collects conjunctions and rashi aspects to that sign
|
|
60
|
+
4. Returns a nested dict keyed by factor, then by varga
|
|
61
|
+
|
|
62
|
+
### Return structure
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
{
|
|
66
|
+
"aspect_type": "quadrant", # which rashi aspect system is in use
|
|
67
|
+
"12 away AK": { # one key per factor
|
|
68
|
+
"9": { # one key per varga
|
|
69
|
+
"conjunction": [ # flat list of planet info strings
|
|
70
|
+
"Mercury,Benefic,Mercury,OH"
|
|
71
|
+
],
|
|
72
|
+
"aspecting": [ # list of lists, grouped by aspecting sign
|
|
73
|
+
["Sun,Malefic,Venus,DB", "Mars,Malefic,Venus,F"],
|
|
74
|
+
["Saturn,Malefic,Saturn,OH"]
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
"-240": { ... },
|
|
78
|
+
"1": { ... }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Planet info strings come from `Planet.jaimini_info()`: `name,nature,lord,dignity`.
|
|
84
|
+
|
|
85
|
+
Aspecting is a list of lists because multiple signs can aspect the target — each inner list contains the planets from one aspecting sign, so the astrologer can see which planets aspect together from the same place.
|
|
86
|
+
|
|
87
|
+
## Why it's built this way
|
|
88
|
+
|
|
89
|
+
The alternative was one function per topic (like the original `get_spiritual_planets()`). That would mean ~10 nearly identical functions differing only in which karaka, which offset, and which vargas. The declarative approach means:
|
|
90
|
+
|
|
91
|
+
- Adding a new topic is one dict in `Gets`, no new code
|
|
92
|
+
- The counting logic (odd/even direction, karaka lookup, cusp resolution) is tested once
|
|
93
|
+
- The output format is consistent across all topics, which makes downstream formatting and TOML export uniform
|
|
94
|
+
|
|
95
|
+
`get_spiritual_planets()` is kept as a thin wrapper for backward compatibility.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# This file is part of libaditya.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (c) 2025 Josh Harper <humanhaven@substack.com>
|
|
4
|
+
#
|
|
5
|
+
# libaditya is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
# (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# libaditya is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
# GNU Affero General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
# along with libaditya. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
from libaditya.objects import Planet
|
|
19
|
+
|
|
20
|
+
class Hellenistic:
|
|
21
|
+
"""
|
|
22
|
+
inherits unto Rashi
|
|
23
|
+
provides calculations used for hellenistic astrology
|
|
24
|
+
|
|
25
|
+
TODO:
|
|
26
|
+
first thing, profections
|
|
27
|
+
Chart().natal().profection() should list the current year lord
|
|
28
|
+
Chart().natal().profection(n) should list the year lord at age n
|
|
29
|
+
also implement monthly, daily, hourly profections
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def profection(self, year=None) -> Planet:
|
|
33
|
+
"""
|
|
34
|
+
return year lord for current year if year is None
|
|
35
|
+
otherwise, for the age year
|
|
36
|
+
"""
|
|
37
|
+
pass
|