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/calc/rashi.py
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
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
|
+
from dataclasses import dataclass, replace
|
|
20
|
+
|
|
21
|
+
from libaditya.objects import Planet, RashiBala
|
|
22
|
+
from libaditya.calc import Varga
|
|
23
|
+
from libaditya.calc import vimshottari
|
|
24
|
+
from libaditya.calc.panchanga import Panchanga
|
|
25
|
+
from libaditya.calc.swe_functions import SWERashi
|
|
26
|
+
from libaditya.calc.hellenistic import Hellenistic
|
|
27
|
+
from libaditya.calc.returns import Returns
|
|
28
|
+
from libaditya.calc.avasthas import (LajjitaadiAvasthas, BaladiAvasthas,
|
|
29
|
+
JagradadiAvasthas, DeeptadiAvasthas,
|
|
30
|
+
ShayanadiAvasthas)
|
|
31
|
+
from libaditya.draw.draw_sbc import DrawSBC
|
|
32
|
+
|
|
33
|
+
from .jaimini_get import JaiminiGet
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class AkritiYoga:
|
|
38
|
+
name: str
|
|
39
|
+
translation: str
|
|
40
|
+
to_move: int
|
|
41
|
+
houses: tuple
|
|
42
|
+
|
|
43
|
+
def __str__(self):
|
|
44
|
+
return f"{self.name} ({self.translation}): {self.to_move} to move — houses {self.houses}"
|
|
45
|
+
|
|
46
|
+
def __repr__(self):
|
|
47
|
+
return f"AkritiYoga({self.name!r}, to_move={self.to_move})"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class NabhasaYoga:
|
|
52
|
+
name: str
|
|
53
|
+
translation: str
|
|
54
|
+
category: str
|
|
55
|
+
to_move: int
|
|
56
|
+
condition: str
|
|
57
|
+
|
|
58
|
+
def __str__(self):
|
|
59
|
+
return f"{self.name} ({self.translation}): {self.to_move} to move — {self.condition}"
|
|
60
|
+
|
|
61
|
+
def __repr__(self):
|
|
62
|
+
return f"NabhasaYoga({self.name!r}, category={self.category!r}, to_move={self.to_move})"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@dataclass
|
|
66
|
+
class MahapurushaYoga:
|
|
67
|
+
name: str
|
|
68
|
+
translation: str
|
|
69
|
+
planet: str
|
|
70
|
+
present: bool
|
|
71
|
+
house: int
|
|
72
|
+
dignity: str
|
|
73
|
+
|
|
74
|
+
def __str__(self):
|
|
75
|
+
if self.present:
|
|
76
|
+
return f"{self.name} ({self.translation}): {self.planet} in house {self.house}, {self.dignity}"
|
|
77
|
+
return f"{self.name} ({self.translation}): not present"
|
|
78
|
+
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
return f"MahapurushaYoga({self.name!r}, planet={self.planet!r}, present={self.present})"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class SolarYoga:
|
|
85
|
+
name: str
|
|
86
|
+
planets: list
|
|
87
|
+
present: bool
|
|
88
|
+
|
|
89
|
+
def __str__(self):
|
|
90
|
+
if self.present:
|
|
91
|
+
return f"{self.name}: {', '.join(self.planets)}"
|
|
92
|
+
return f"{self.name}: not present"
|
|
93
|
+
|
|
94
|
+
def __repr__(self):
|
|
95
|
+
return f"SolarYoga({self.name!r}, present={self.present})"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class LunarYoga:
|
|
100
|
+
name: str
|
|
101
|
+
planets: list
|
|
102
|
+
present: bool
|
|
103
|
+
|
|
104
|
+
def __str__(self):
|
|
105
|
+
if self.present:
|
|
106
|
+
return f"{self.name}: {', '.join(self.planets)}"
|
|
107
|
+
return f"{self.name}: not present"
|
|
108
|
+
|
|
109
|
+
def __repr__(self):
|
|
110
|
+
return f"LunarYoga({self.name!r}, present={self.present})"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class Rashi(Varga,SWERashi,JaiminiGet,RashiBala,DrawSBC,Hellenistic,Returns,LajjitaadiAvasthas,BaladiAvasthas,JagradadiAvasthas,DeeptadiAvasthas,ShayanadiAvasthas):
|
|
114
|
+
|
|
115
|
+
def __init__(self,context,chart):
|
|
116
|
+
self.master = chart
|
|
117
|
+
super().__init__(context=context,amsha=1)
|
|
118
|
+
self._dig_balas = self.init_dig_balas()
|
|
119
|
+
self._saptavargaja_balas = self.init_saptavargaja_balas()
|
|
120
|
+
self._sama_visama_balas = self.init_sama_visama_balas()
|
|
121
|
+
self._kendradi_balas = self.init_kendradi_balas()
|
|
122
|
+
self._drig_balas = self.init_drig_balas()
|
|
123
|
+
self._lajjitaadi_avasthas = self.lajjitaadi_avasthas()
|
|
124
|
+
self._baladi_avasthas = self.baladi_avasthas()
|
|
125
|
+
self._jagradadi_avasthas = self.jagradadi_avasthas()
|
|
126
|
+
self._deeptadi_avasthas = self.deeptadi_avasthas()
|
|
127
|
+
self._shayanadi_avasthas = self.shayanadi_avasthas()
|
|
128
|
+
|
|
129
|
+
def planets(self):
|
|
130
|
+
return self._planets
|
|
131
|
+
|
|
132
|
+
def ecliptic(self):
|
|
133
|
+
return self._ecliptic
|
|
134
|
+
|
|
135
|
+
def cusps(self):
|
|
136
|
+
return self._cusps
|
|
137
|
+
|
|
138
|
+
def signs(self):
|
|
139
|
+
return self._signs
|
|
140
|
+
|
|
141
|
+
def avasthas(self):
|
|
142
|
+
from libaditya import print_functions as printf
|
|
143
|
+
printf.print_avasthas(self._lajjitaadi_avasthas,
|
|
144
|
+
self._baladi_avasthas,
|
|
145
|
+
self._jagradadi_avasthas,
|
|
146
|
+
self._deeptadi_avasthas,
|
|
147
|
+
self._shayanadi_avasthas)
|
|
148
|
+
|
|
149
|
+
def house_position(self, planet: str, hsys=None) -> float:
|
|
150
|
+
"""
|
|
151
|
+
a wrapper for the function swe.house_pos()
|
|
152
|
+
planet is the Planet.identity(), i.e., the english name of the desired planet
|
|
153
|
+
"""
|
|
154
|
+
armc = self.cusps().armc()
|
|
155
|
+
lat = self.context.location.latitude()
|
|
156
|
+
eo = self.context.timeJD.ecliptic_obliquity()
|
|
157
|
+
planet = self.planets()[planet]
|
|
158
|
+
planet_coords = (planet.ecliptic_longitude(),planet.latitude())
|
|
159
|
+
if hsys == None:
|
|
160
|
+
hsys = self.context.hsys
|
|
161
|
+
return swe.house_pos(armc,lat,eo,planet_coords,hsys.encode())
|
|
162
|
+
|
|
163
|
+
def Master(self):
|
|
164
|
+
"""
|
|
165
|
+
return the Chart that spawned it
|
|
166
|
+
"""
|
|
167
|
+
return self.master
|
|
168
|
+
|
|
169
|
+
def panchanga(self, **kwargs):
|
|
170
|
+
"""
|
|
171
|
+
panchanga is here because it has to do with the sun and moon, with time
|
|
172
|
+
that is the Rashi chart essentially
|
|
173
|
+
none of the other vargas really need a separate class, because they are really subsections of this class
|
|
174
|
+
which is why Rashi can hopefully reach all the Vargas
|
|
175
|
+
|
|
176
|
+
Panchanga.__str__ prints the basic panchagna, and also the panchanga addendum
|
|
177
|
+
__repr__ prints only the basic time and panchanga information
|
|
178
|
+
"""
|
|
179
|
+
context = replace(self.context,**kwargs)
|
|
180
|
+
return Panchanga(context)
|
|
181
|
+
|
|
182
|
+
def print_current_vimshottari_dasha(self,yrlen="saura",levels=5):
|
|
183
|
+
vimshottari.print_current_vdasha(self.context,yrlen,levels)
|
|
184
|
+
return
|
|
185
|
+
|
|
186
|
+
def rashi_argala(self) -> [[Planet],[Planet],[Planet]]:
|
|
187
|
+
"""
|
|
188
|
+
it returns a list a lists, where each sublist is the combinatino of the corresponding argala lists of lagna and seventh
|
|
189
|
+
|
|
190
|
+
this combines the argala formed to both 1st and 7th
|
|
191
|
+
"""
|
|
192
|
+
lagna_arg = self.argala(self.signs().lagna())
|
|
193
|
+
seventh_arg = self.argala(self.signs()[self.signs().lagna().astrological_signs_forward(7)])
|
|
194
|
+
ret = [[],[],[]]
|
|
195
|
+
for n,arg in enumerate(lagna_arg):
|
|
196
|
+
for planet in lagna_arg[n]:
|
|
197
|
+
ret[n].append(planet)
|
|
198
|
+
for planet in seventh_arg[n]:
|
|
199
|
+
ret[n].append(planet)
|
|
200
|
+
return ret
|
|
201
|
+
# each arg has three elements; put all of lagna_arg[0] together with seventh_arg[0], etc.
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def akriti_yogas(self):
|
|
205
|
+
"""
|
|
206
|
+
find the 20 akriti yogas in this Rashi varga
|
|
207
|
+
these are rarely found perfectly or completely, so we find
|
|
208
|
+
how many planets would need to be moved to create each
|
|
209
|
+
for these yogas, planets means the seven embodied planets, i.e., karakas (Sun-Saturn)
|
|
210
|
+
returns a list of AkritiYoga dataclasses sorted by to_move ascending
|
|
211
|
+
"""
|
|
212
|
+
akritis = []
|
|
213
|
+
lagna_sign = self.signs().lagna()
|
|
214
|
+
# karaka counts per house (1-indexed by house number from lagna)
|
|
215
|
+
h = {}
|
|
216
|
+
for i in range(1, 13):
|
|
217
|
+
h[i] = self.signs()[lagna_sign.astrological_signs_forward(i)].how_many_karakas()
|
|
218
|
+
|
|
219
|
+
# for vajra/yava: count benefic and malefic karakas per house
|
|
220
|
+
# uses fixed natural classification: Moon, Mercury, Jupiter, Venus = benefic
|
|
221
|
+
# Sun, Mars, Saturn = malefic
|
|
222
|
+
FIXED_MALEFICS = {"Sun", "Mars", "Saturn"}
|
|
223
|
+
bh = {} # benefic karaka count per house
|
|
224
|
+
mh = {} # malefic karaka count per house
|
|
225
|
+
for i in range(1, 13):
|
|
226
|
+
sign = self.signs()[lagna_sign.astrological_signs_forward(i)]
|
|
227
|
+
karakas = sign.karakas()
|
|
228
|
+
b = 0
|
|
229
|
+
m = 0
|
|
230
|
+
for k in karakas:
|
|
231
|
+
if k.identity() in FIXED_MALEFICS:
|
|
232
|
+
m += 1
|
|
233
|
+
else:
|
|
234
|
+
b += 1
|
|
235
|
+
bh[i] = b
|
|
236
|
+
mh[i] = m
|
|
237
|
+
|
|
238
|
+
def tm(*houses):
|
|
239
|
+
"""to_move: how many of the 7 karakas are outside the given houses"""
|
|
240
|
+
return 7 - sum(h[i] for i in houses)
|
|
241
|
+
|
|
242
|
+
def tm_dist(*houses):
|
|
243
|
+
"""to_move for yogas requiring distribution across houses.
|
|
244
|
+
accounts for both planets outside AND empty required houses,
|
|
245
|
+
since a planet must be moved into each empty house."""
|
|
246
|
+
outside = 7 - sum(h[i] for i in houses)
|
|
247
|
+
empty = sum(1 for i in houses if h[i] == 0)
|
|
248
|
+
return max(outside, empty)
|
|
249
|
+
|
|
250
|
+
# --- trine yogas ---
|
|
251
|
+
akritis.append(AkritiYoga("Sringataka", "mountain having three peaks",
|
|
252
|
+
tm(1, 5, 9), (1, 5, 9)))
|
|
253
|
+
akritis.append(AkritiYoga("Hala Artha", "plough",
|
|
254
|
+
tm(2, 6, 10), (2, 6, 10)))
|
|
255
|
+
akritis.append(AkritiYoga("Hala Kama", "plough",
|
|
256
|
+
tm(3, 7, 11), (3, 7, 11)))
|
|
257
|
+
akritis.append(AkritiYoga("Hala Moksha", "plough",
|
|
258
|
+
tm(4, 8, 12), (4, 8, 12)))
|
|
259
|
+
|
|
260
|
+
# --- gada yogas: all planets in two successive angles ---
|
|
261
|
+
akritis.append(AkritiYoga("Gada 1/4", "mace",
|
|
262
|
+
tm(1, 4), (1, 4)))
|
|
263
|
+
akritis.append(AkritiYoga("Gada 4/7", "mace",
|
|
264
|
+
tm(4, 7), (4, 7)))
|
|
265
|
+
akritis.append(AkritiYoga("Gada 7/10", "mace",
|
|
266
|
+
tm(7, 10), (7, 10)))
|
|
267
|
+
akritis.append(AkritiYoga("Gada 10/1", "mace",
|
|
268
|
+
tm(10, 1), (10, 1)))
|
|
269
|
+
|
|
270
|
+
# --- two-house angle yogas ---
|
|
271
|
+
akritis.append(AkritiYoga("Sakata", "cart",
|
|
272
|
+
tm(1, 7), (1, 7)))
|
|
273
|
+
akritis.append(AkritiYoga("Vihaga", "skygoer",
|
|
274
|
+
tm(4, 10), (4, 10)))
|
|
275
|
+
|
|
276
|
+
# --- four-house yogas ---
|
|
277
|
+
akritis.append(AkritiYoga("Kamala", "lotus",
|
|
278
|
+
tm(1, 4, 7, 10), (1, 4, 7, 10)))
|
|
279
|
+
akritis.append(AkritiYoga("Vapi Panaphara", "pond",
|
|
280
|
+
tm(2, 5, 8, 11), (2, 5, 8, 11)))
|
|
281
|
+
akritis.append(AkritiYoga("Vapi Apoklima", "pond",
|
|
282
|
+
tm(3, 6, 9, 12), (3, 6, 9, 12)))
|
|
283
|
+
|
|
284
|
+
# --- vajra and yava: benefic/malefic distribution in angles ---
|
|
285
|
+
# vajra: all benefics in 1 & 7, all malefics in 4 & 10
|
|
286
|
+
vajra_correct = (bh[1] + bh[7]) + (mh[4] + mh[10])
|
|
287
|
+
akritis.append(AkritiYoga("Vajra", "thunderbolt",
|
|
288
|
+
7 - vajra_correct, (1, 4, 7, 10)))
|
|
289
|
+
# yava: all malefics in 1 & 7, all benefics in 4 & 10
|
|
290
|
+
yava_correct = (mh[1] + mh[7]) + (bh[4] + bh[10])
|
|
291
|
+
akritis.append(AkritiYoga("Yava", "barleycorn",
|
|
292
|
+
7 - yava_correct, (1, 4, 7, 10)))
|
|
293
|
+
|
|
294
|
+
# --- four consecutive house yogas ---
|
|
295
|
+
akritis.append(AkritiYoga("Yupa", "sacrificial pillar",
|
|
296
|
+
tm(1, 2, 3, 4), (1, 2, 3, 4)))
|
|
297
|
+
akritis.append(AkritiYoga("Sara", "arrow",
|
|
298
|
+
tm(4, 5, 6, 7), (4, 5, 6, 7)))
|
|
299
|
+
akritis.append(AkritiYoga("Shakti", "power",
|
|
300
|
+
tm(7, 8, 9, 10), (7, 8, 9, 10)))
|
|
301
|
+
akritis.append(AkritiYoga("Danda", "rod",
|
|
302
|
+
tm(10, 11, 12, 1), (10, 11, 12, 1)))
|
|
303
|
+
|
|
304
|
+
# --- seven consecutive house yogas (use tm_dist for distribution) ---
|
|
305
|
+
akritis.append(AkritiYoga("Nauka", "boat",
|
|
306
|
+
tm_dist(1, 2, 3, 4, 5, 6, 7), (1, 2, 3, 4, 5, 6, 7)))
|
|
307
|
+
akritis.append(AkritiYoga("Kuta", "peak",
|
|
308
|
+
tm_dist(4, 5, 6, 7, 8, 9, 10), (4, 5, 6, 7, 8, 9, 10)))
|
|
309
|
+
akritis.append(AkritiYoga("Chatra", "parasol",
|
|
310
|
+
tm_dist(7, 8, 9, 10, 11, 12, 1), (7, 8, 9, 10, 11, 12, 1)))
|
|
311
|
+
akritis.append(AkritiYoga("Chapa", "bow",
|
|
312
|
+
tm_dist(10, 11, 12, 1, 2, 3, 4), (10, 11, 12, 1, 2, 3, 4)))
|
|
313
|
+
|
|
314
|
+
# --- ardha chandra: seven consecutive from a panaphara or apoklima ---
|
|
315
|
+
akritis.append(AkritiYoga("Ardha Chandra Artha Panaphara", "half moon",
|
|
316
|
+
tm_dist(2, 3, 4, 5, 6, 7, 8), (2, 3, 4, 5, 6, 7, 8)))
|
|
317
|
+
akritis.append(AkritiYoga("Ardha Chandra Dharma Panaphara", "half moon",
|
|
318
|
+
tm_dist(5, 6, 7, 8, 9, 10, 11), (5, 6, 7, 8, 9, 10, 11)))
|
|
319
|
+
akritis.append(AkritiYoga("Ardha Chandra Moksha Panaphara", "half moon",
|
|
320
|
+
tm_dist(8, 9, 10, 11, 12, 1, 2), (8, 9, 10, 11, 12, 1, 2)))
|
|
321
|
+
akritis.append(AkritiYoga("Ardha Chandra Kama Panaphara", "half moon",
|
|
322
|
+
tm_dist(11, 12, 1, 2, 3, 4, 5), (11, 12, 1, 2, 3, 4, 5)))
|
|
323
|
+
akritis.append(AkritiYoga("Ardha Chandra Kama Apoklima", "half moon",
|
|
324
|
+
tm_dist(3, 4, 5, 6, 7, 8, 9), (3, 4, 5, 6, 7, 8, 9)))
|
|
325
|
+
akritis.append(AkritiYoga("Ardha Chandra Artha Apoklima", "half moon",
|
|
326
|
+
tm_dist(6, 7, 8, 9, 10, 11, 12), (6, 7, 8, 9, 10, 11, 12)))
|
|
327
|
+
akritis.append(AkritiYoga("Ardha Chandra Dharma Apoklima", "half moon",
|
|
328
|
+
tm_dist(9, 10, 11, 12, 1, 2, 3), (9, 10, 11, 12, 1, 2, 3)))
|
|
329
|
+
akritis.append(AkritiYoga("Ardha Chandra Moksha Apoklima", "half moon",
|
|
330
|
+
tm_dist(12, 1, 2, 3, 4, 5, 6), (12, 1, 2, 3, 4, 5, 6)))
|
|
331
|
+
|
|
332
|
+
# --- six alternate house yogas (use tm_dist for distribution) ---
|
|
333
|
+
akritis.append(AkritiYoga("Chakra", "wheel",
|
|
334
|
+
tm_dist(1, 3, 5, 7, 9, 11), (1, 3, 5, 7, 9, 11)))
|
|
335
|
+
akritis.append(AkritiYoga("Samudra", "sea",
|
|
336
|
+
tm_dist(2, 4, 6, 8, 10, 12), (2, 4, 6, 8, 10, 12)))
|
|
337
|
+
|
|
338
|
+
akritis.sort(key=lambda y: y.to_move)
|
|
339
|
+
return akritis
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def ashraya_yogas(self):
|
|
343
|
+
"""
|
|
344
|
+
Ashraya ("resting place") yogas: 3 yogas based on the modality
|
|
345
|
+
of the signs the 7 karakas rest in.
|
|
346
|
+
Rajju = all in movable, Musala = all in fixed, Nala = all in dual.
|
|
347
|
+
"""
|
|
348
|
+
lagna_sign = self.signs().lagna()
|
|
349
|
+
movable = 0
|
|
350
|
+
fixed = 0
|
|
351
|
+
dual = 0
|
|
352
|
+
for i in range(1, 13):
|
|
353
|
+
sign = self.signs()[lagna_sign.astrological_signs_forward(i)]
|
|
354
|
+
n = sign.how_many_karakas()
|
|
355
|
+
mod = sign.modality()
|
|
356
|
+
if mod == "Moveable":
|
|
357
|
+
movable += n
|
|
358
|
+
elif mod == "Fixed":
|
|
359
|
+
fixed += n
|
|
360
|
+
else:
|
|
361
|
+
dual += n
|
|
362
|
+
|
|
363
|
+
yogas = [
|
|
364
|
+
NabhasaYoga("Rajju", "rope", "Ashraya", 7 - movable,
|
|
365
|
+
"all planets in movable signs"),
|
|
366
|
+
NabhasaYoga("Musala", "pestle", "Ashraya", 7 - fixed,
|
|
367
|
+
"all planets in fixed signs"),
|
|
368
|
+
NabhasaYoga("Nala", "reed", "Ashraya", 7 - dual,
|
|
369
|
+
"all planets in dual signs"),
|
|
370
|
+
]
|
|
371
|
+
yogas.sort(key=lambda y: y.to_move)
|
|
372
|
+
return yogas
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def dala_yogas(self):
|
|
376
|
+
"""
|
|
377
|
+
Dala ("petal") yogas: 2 yogas based on benefic/malefic occupation
|
|
378
|
+
of the kendras (houses 1, 4, 7, 10).
|
|
379
|
+
Mala = all benefics in kendras, Sarpa = all malefics in kendras.
|
|
380
|
+
Uses each planet's actual nature (Moon varies by phase).
|
|
381
|
+
"""
|
|
382
|
+
lagna_sign = self.signs().lagna()
|
|
383
|
+
kendras = {1, 4, 7, 10}
|
|
384
|
+
benefics_in_kendras = 0
|
|
385
|
+
malefics_in_kendras = 0
|
|
386
|
+
total_benefics = 0
|
|
387
|
+
total_malefics = 0
|
|
388
|
+
|
|
389
|
+
for i in range(1, 13):
|
|
390
|
+
sign = self.signs()[lagna_sign.astrological_signs_forward(i)]
|
|
391
|
+
for planet in sign.karakas():
|
|
392
|
+
if planet.nature() == "Benefic":
|
|
393
|
+
total_benefics += 1
|
|
394
|
+
if i in kendras:
|
|
395
|
+
benefics_in_kendras += 1
|
|
396
|
+
else:
|
|
397
|
+
total_malefics += 1
|
|
398
|
+
if i in kendras:
|
|
399
|
+
malefics_in_kendras += 1
|
|
400
|
+
|
|
401
|
+
yogas = [
|
|
402
|
+
NabhasaYoga("Mala", "garland", "Dala",
|
|
403
|
+
total_benefics - benefics_in_kendras,
|
|
404
|
+
"all benefics in kendras"),
|
|
405
|
+
NabhasaYoga("Sarpa", "serpent", "Dala",
|
|
406
|
+
total_malefics - malefics_in_kendras,
|
|
407
|
+
"all malefics in kendras"),
|
|
408
|
+
]
|
|
409
|
+
yogas.sort(key=lambda y: y.to_move)
|
|
410
|
+
return yogas
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def sankhya_yogas(self):
|
|
414
|
+
"""
|
|
415
|
+
Sankhya ("number") yogas: 7 yogas based on how many houses
|
|
416
|
+
the 7 karakas occupy. Exactly one is always active (to_move=0).
|
|
417
|
+
"""
|
|
418
|
+
lagna_sign = self.signs().lagna()
|
|
419
|
+
occupied = 0
|
|
420
|
+
for i in range(1, 13):
|
|
421
|
+
if self.signs()[lagna_sign.astrological_signs_forward(i)].how_many_karakas() > 0:
|
|
422
|
+
occupied += 1
|
|
423
|
+
|
|
424
|
+
sankhya_defs = [
|
|
425
|
+
("Veena", "lute", 7),
|
|
426
|
+
("Dama", "garland", 6),
|
|
427
|
+
("Pasa", "noose", 5),
|
|
428
|
+
("Kedara", "field", 4),
|
|
429
|
+
("Sula", "spike", 3),
|
|
430
|
+
("Yuga", "yoke", 2),
|
|
431
|
+
("Gola", "globe", 1),
|
|
432
|
+
]
|
|
433
|
+
yogas = []
|
|
434
|
+
for name, trans, required in sankhya_defs:
|
|
435
|
+
yogas.append(NabhasaYoga(name, trans, "Sankhya",
|
|
436
|
+
abs(occupied - required),
|
|
437
|
+
f"planets in {required} houses"))
|
|
438
|
+
yogas.sort(key=lambda y: y.to_move)
|
|
439
|
+
return yogas
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
def nabhasa_yogas(self):
|
|
443
|
+
"""
|
|
444
|
+
All 32 Nabhasa yogas: Ashraya (3) + Dala (2) + Sankhya (7) + Akriti (20).
|
|
445
|
+
Returns a list of mixed NabhasaYoga and AkritiYoga dataclasses,
|
|
446
|
+
sorted by to_move ascending.
|
|
447
|
+
"""
|
|
448
|
+
all_yogas = self.ashraya_yogas() + self.dala_yogas() + self.sankhya_yogas() + self.akriti_yogas()
|
|
449
|
+
all_yogas.sort(key=lambda y: y.to_move)
|
|
450
|
+
return all_yogas
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
def panchamahapurusha_yogas(self):
|
|
454
|
+
"""
|
|
455
|
+
Panchamahapurusha yogas: Mars, Mercury, Jupiter, Venus, or Saturn
|
|
456
|
+
in an angle (house 1, 4, 7, 10) AND in own, moolatrikona, or exaltation sign.
|
|
457
|
+
Returns a list of 5 MahapurushaYoga dataclasses.
|
|
458
|
+
"""
|
|
459
|
+
defs = [
|
|
460
|
+
("Ruchaka", "radiant", "Mars"),
|
|
461
|
+
("Bhadra", "blessed", "Mercury"),
|
|
462
|
+
("Hamsa", "swan", "Jupiter"),
|
|
463
|
+
("Malavya", "of Malava", "Venus"),
|
|
464
|
+
("Sasa", "rabbit", "Saturn"),
|
|
465
|
+
]
|
|
466
|
+
yogas = []
|
|
467
|
+
for name, trans, planet_name in defs:
|
|
468
|
+
sign = self.signs().where_is(planet_name)
|
|
469
|
+
house = sign.rashis_from_lagna()
|
|
470
|
+
dig = self.planets()[planet_name].dignity()
|
|
471
|
+
in_angle = house in (1, 4, 7, 10)
|
|
472
|
+
in_own_or_ex = dig in ("OH", "EX", "MT")
|
|
473
|
+
present = in_angle and in_own_or_ex
|
|
474
|
+
yogas.append(MahapurushaYoga(name, trans, planet_name,
|
|
475
|
+
present, house, dig))
|
|
476
|
+
return yogas
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def solar_yogas(self):
|
|
480
|
+
"""
|
|
481
|
+
Solar yogas based on starry planets (Mars, Mercury, Jupiter, Venus, Saturn)
|
|
482
|
+
— NOT Moon, Rahu, or Ketu — in the 2nd and/or 12th from the Sun.
|
|
483
|
+
Vosi: planet(s) in the 12th from Sun (rises before Sun)
|
|
484
|
+
Vesi: planet(s) in the 2nd from Sun (sets after Sun)
|
|
485
|
+
Ubhayachari: planets in both 2nd and 12th from Sun
|
|
486
|
+
"""
|
|
487
|
+
sun_sign = self.signs().where_is("Sun")
|
|
488
|
+
sun_house = sun_sign.rashis_from_lagna()
|
|
489
|
+
lagna_sign = self.signs().lagna()
|
|
490
|
+
# house numbers of 2nd and 12th from Sun
|
|
491
|
+
h12_from_sun = ((sun_house - 2) % 12) + 1 # 12th from Sun
|
|
492
|
+
h2_from_sun = (sun_house % 12) + 1 # 2nd from Sun
|
|
493
|
+
|
|
494
|
+
STARRY = {"Mars", "Mercury", "Jupiter", "Venus", "Saturn"}
|
|
495
|
+
sign_12 = self.signs()[lagna_sign.astrological_signs_forward(h12_from_sun)]
|
|
496
|
+
sign_2 = self.signs()[lagna_sign.astrological_signs_forward(h2_from_sun)]
|
|
497
|
+
|
|
498
|
+
vosi_planets = [p.identity() for p in sign_12.karakas()
|
|
499
|
+
if p.identity() in STARRY]
|
|
500
|
+
vesi_planets = [p.identity() for p in sign_2.karakas()
|
|
501
|
+
if p.identity() in STARRY]
|
|
502
|
+
|
|
503
|
+
yogas = [
|
|
504
|
+
SolarYoga("Vosi", vosi_planets, len(vosi_planets) > 0),
|
|
505
|
+
SolarYoga("Vesi", vesi_planets, len(vesi_planets) > 0),
|
|
506
|
+
SolarYoga("Ubhayachari", vosi_planets + vesi_planets,
|
|
507
|
+
len(vosi_planets) > 0 and len(vesi_planets) > 0),
|
|
508
|
+
]
|
|
509
|
+
return yogas
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def lunar_yogas(self):
|
|
513
|
+
"""
|
|
514
|
+
Lunar yogas based on planets (not Sun, Rahu, Ketu) in the
|
|
515
|
+
2nd and/or 12th from the Moon.
|
|
516
|
+
Anapha: planet(s) in the 12th from Moon
|
|
517
|
+
Sunapha: planet(s) in the 2nd from Moon
|
|
518
|
+
Durudhara: planets in both 2nd and 12th from Moon
|
|
519
|
+
Kemadruma: none of the above
|
|
520
|
+
"""
|
|
521
|
+
moon_sign = self.signs().where_is("Moon")
|
|
522
|
+
moon_house = moon_sign.rashis_from_lagna()
|
|
523
|
+
lagna_sign = self.signs().lagna()
|
|
524
|
+
h12_from_moon = ((moon_house - 2) % 12) + 1
|
|
525
|
+
h2_from_moon = (moon_house % 12) + 1
|
|
526
|
+
|
|
527
|
+
ELIGIBLE = {"Mars", "Mercury", "Jupiter", "Venus", "Saturn"}
|
|
528
|
+
sign_12 = self.signs()[lagna_sign.astrological_signs_forward(h12_from_moon)]
|
|
529
|
+
sign_2 = self.signs()[lagna_sign.astrological_signs_forward(h2_from_moon)]
|
|
530
|
+
|
|
531
|
+
anapha_planets = [p.identity() for p in sign_12.karakas()
|
|
532
|
+
if p.identity() in ELIGIBLE]
|
|
533
|
+
sunapha_planets = [p.identity() for p in sign_2.karakas()
|
|
534
|
+
if p.identity() in ELIGIBLE]
|
|
535
|
+
|
|
536
|
+
has_anapha = len(anapha_planets) > 0
|
|
537
|
+
has_sunapha = len(sunapha_planets) > 0
|
|
538
|
+
|
|
539
|
+
yogas = [
|
|
540
|
+
LunarYoga("Anapha", anapha_planets, has_anapha),
|
|
541
|
+
LunarYoga("Sunapha", sunapha_planets, has_sunapha),
|
|
542
|
+
LunarYoga("Durudhara", anapha_planets + sunapha_planets,
|
|
543
|
+
has_anapha and has_sunapha),
|
|
544
|
+
LunarYoga("Kemadruma", [], not has_anapha and not has_sunapha),
|
|
545
|
+
]
|
|
546
|
+
return yogas
|
|
547
|
+
|
|
548
|
+
def jaimini_kemadruma(self):
|
|
549
|
+
"""
|
|
550
|
+
Jaimini Kemadruma Yoga (1.2.119-120)
|
|
551
|
+
|
|
552
|
+
from the svamsha (AK in D9), lagna, or pada:
|
|
553
|
+
if there are an equal number of malefics in the 2nd and 8th,
|
|
554
|
+
with no benefics in either house, that is kemadruma yoga
|
|
555
|
+
|
|
556
|
+
count backward if the reference sign is even (jaimini direction rule)
|
|
557
|
+
malefics are planets where .nature() == "Malefic"
|
|
558
|
+
|
|
559
|
+
also checks from AK in rashi (D1)
|
|
560
|
+
|
|
561
|
+
moon aspecting the malefics makes it more severe (1.2.120)
|
|
562
|
+
|
|
563
|
+
returns a list of dicts, one per reference point where kemadruma is present
|
|
564
|
+
each dict has: reference, second_malefics, eighth_malefics, moon_aspects, sign
|
|
565
|
+
"""
|
|
566
|
+
ak = self.planets().jaimini_karakas()[0]
|
|
567
|
+
d9 = self.master.varga(9)
|
|
568
|
+
|
|
569
|
+
# reference points: (name, sign, varga to use)
|
|
570
|
+
refs = [
|
|
571
|
+
("lagna", self.lagna(), self),
|
|
572
|
+
("AK in D1", self.signs().where_is(ak.identity()), self),
|
|
573
|
+
("pada", self.pada(), self),
|
|
574
|
+
("svamsha", d9.where_is(ak.identity()), d9),
|
|
575
|
+
]
|
|
576
|
+
|
|
577
|
+
moon_sign = self.signs()[self.planets().moon().sign()]
|
|
578
|
+
|
|
579
|
+
results = []
|
|
580
|
+
for name, ref_sign, varga in refs:
|
|
581
|
+
direction = 1 if ref_sign.sign() % 2 == 1 else -1
|
|
582
|
+
second = varga.signs()[ref_sign.astrological_signs_forward(2 * direction)]
|
|
583
|
+
eighth = varga.signs()[ref_sign.astrological_signs_forward(8 * direction)]
|
|
584
|
+
|
|
585
|
+
second_malefics = [p for p in second.grahas() if p.nature() == "Malefic"]
|
|
586
|
+
eighth_malefics = [p for p in eighth.grahas() if p.nature() == "Malefic"]
|
|
587
|
+
second_benefics = [p for p in second.grahas() if p.nature() == "Benefic"]
|
|
588
|
+
eighth_benefics = [p for p in eighth.grahas() if p.nature() == "Benefic"]
|
|
589
|
+
|
|
590
|
+
if (len(second_malefics) == 0 or len(eighth_malefics) == 0):
|
|
591
|
+
continue
|
|
592
|
+
if len(second_malefics) != len(eighth_malefics):
|
|
593
|
+
continue
|
|
594
|
+
if second_benefics or eighth_benefics:
|
|
595
|
+
continue
|
|
596
|
+
|
|
597
|
+
# check if moon aspects either house (1.2.120 — more severe)
|
|
598
|
+
moon_aspects_second = self.signs().rashi_aspect_from_to(moon_sign, second)
|
|
599
|
+
moon_aspects_eighth = self.signs().rashi_aspect_from_to(moon_sign, eighth)
|
|
600
|
+
|
|
601
|
+
results.append({
|
|
602
|
+
"reference": name,
|
|
603
|
+
"sign": ref_sign,
|
|
604
|
+
"second": second,
|
|
605
|
+
"second_malefics": second_malefics,
|
|
606
|
+
"eighth": eighth,
|
|
607
|
+
"eighth_malefics": eighth_malefics,
|
|
608
|
+
"moon_aspects": moon_aspects_second or moon_aspects_eighth,
|
|
609
|
+
})
|
|
610
|
+
|
|
611
|
+
return results
|
|
612
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
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 EphContext, Sun
|
|
19
|
+
|
|
20
|
+
class Returns:
|
|
21
|
+
"""
|
|
22
|
+
inherits unto Rashi
|
|
23
|
+
provides calculations for returns, e.g., solar return, etc.
|
|
24
|
+
|
|
25
|
+
TODO:
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def solar_return(self, year: int = None) -> EphContext:
|
|
29
|
+
"""
|
|
30
|
+
return EphContext for the next time the Sun is at the same degree at it is in this Rashi
|
|
31
|
+
|
|
32
|
+
if year is None, solar_return will calculate for the current year of the persons life
|
|
33
|
+
i.e., year=0 is the birth year; year=1 is the next time it is at that degree
|
|
34
|
+
|
|
35
|
+
of if you are 36, Rashi().solar_return() will give the current solar return chart for the time
|
|
36
|
+
in between being 36 and 37
|
|
37
|
+
"""
|
|
38
|
+
if year == None:
|
|
39
|
+
year = int(self.context.timeJD.current_age())
|
|
40
|
+
context = self.context
|
|
41
|
+
original_sun = self.planets().sun()
|
|
42
|
+
return_longitude = original_sun.ecliptic_longitude()
|
|
43
|
+
while year > 0:
|
|
44
|
+
this_sun = Sun(context)
|
|
45
|
+
# move it forward slightly, so that when we ingress it to its ecliptic_longitude, its find the next time it is there
|
|
46
|
+
this_sun = this_sun.ingress(this_sun.ecliptic_longitude()+.1)
|
|
47
|
+
next_sun = this_sun.ingress(return_longitude)
|
|
48
|
+
context = next_sun.context
|
|
49
|
+
year -= 1
|
|
50
|
+
return self.master._new_context(context)
|