libephemeris 0.1.6__tar.gz → 0.1.8__tar.gz
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.
- libephemeris-0.1.8/PKG-INFO +301 -0
- libephemeris-0.1.8/README.md +265 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/__init__.py +15 -41
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/planets.py +54 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/state.py +51 -9
- libephemeris-0.1.8/libephemeris/utils.py +77 -0
- libephemeris-0.1.8/libephemeris.egg-info/PKG-INFO +301 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/pyproject.toml +1 -1
- libephemeris-0.1.6/PKG-INFO +0 -376
- libephemeris-0.1.6/README.md +0 -340
- libephemeris-0.1.6/libephemeris/utils.py +0 -36
- libephemeris-0.1.6/libephemeris.egg-info/PKG-INFO +0 -376
- {libephemeris-0.1.6 → libephemeris-0.1.8}/LICENSE +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/MANIFEST.in +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/angles.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/arabic_parts.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/constants.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/crossing.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/fixed_stars.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/houses.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/lunar.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/minor_bodies.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris/time_utils.py +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris.egg-info/SOURCES.txt +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris.egg-info/dependency_links.txt +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris.egg-info/requires.txt +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/libephemeris.egg-info/top_level.txt +0 -0
- {libephemeris-0.1.6 → libephemeris-0.1.8}/setup.cfg +0 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: libephemeris
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: A high-precision, open-source astronomical ephemeris library for Python, powered by Skyfield.
|
|
5
|
+
Author-email: Giacomo Battaglia <giacomo.battaglia@example.com>
|
|
6
|
+
License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
7
|
+
Version 3, 29 June 2007
|
|
8
|
+
|
|
9
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
10
|
+
Everyone is permitted to copy and distribute verbatim copies
|
|
11
|
+
of this license document, but changing it is not allowed.
|
|
12
|
+
|
|
13
|
+
This version of the GNU Lesser General Public License incorporates
|
|
14
|
+
the terms and conditions of version 3 of the GNU General Public
|
|
15
|
+
License, supplemented by the additional permissions listed below.
|
|
16
|
+
|
|
17
|
+
[... Please replace this with the full text of the LGPL v3 License ...]
|
|
18
|
+
[... Available at: https://www.gnu.org/licenses/lgpl-3.0.txt ...]
|
|
19
|
+
|
|
20
|
+
Project-URL: Homepage, https://github.com/g-battaglia/libephemeris
|
|
21
|
+
Project-URL: Repository, https://github.com/g-battaglia/libephemeris
|
|
22
|
+
Project-URL: Issues, https://github.com/g-battaglia/libephemeris/issues
|
|
23
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
24
|
+
Classifier: Intended Audience :: Science/Research
|
|
25
|
+
Classifier: Intended Audience :: Developers
|
|
26
|
+
Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
|
|
27
|
+
Classifier: Programming Language :: Python :: 3
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
29
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
30
|
+
Requires-Python: >=3.10
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: skyfield>=1.53
|
|
34
|
+
Requires-Dist: skyfield-data>=7.0.0
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# LibEphemeris
|
|
38
|
+
|
|
39
|
+
**High-precision astronomical ephemeris library for Python (Swiss Ephemeris compatible, powered by Skyfield and JPL DE ephemerides).**
|
|
40
|
+
|
|
41
|
+
> [!WARNING]
|
|
42
|
+
> **Pre-Alpha Release**
|
|
43
|
+
>
|
|
44
|
+
> LibEphemeris is currently in an early pre-alpha stage. The public API is unstable and may change without notice. Do not rely on it in production yet.
|
|
45
|
+
|
|
46
|
+
LibEphemeris is an open-source alternative to Swiss Ephemeris that provides scientific-grade astronomical calculations using NASA JPL ephemerides via [Skyfield](https://rhodesmill.org/skyfield/). The goal is to mirror the Swiss Ephemeris API (as exposed by `pyswisseph`) while using modern, freely available data and a pure-Python implementation.
|
|
47
|
+
|
|
48
|
+
[](https://www.gnu.org/licenses/lgpl-3.0)
|
|
49
|
+
[](https://www.python.org)
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Features at a Glance
|
|
54
|
+
|
|
55
|
+
- **Planetary positions**: Sun, Moon, all major planets and Pluto.
|
|
56
|
+
- **High precision**: Based on NASA JPL DE421 by default (configurable to other DE files).
|
|
57
|
+
- **Multiple coordinate systems**: Ecliptic, equatorial, J2000 and of-date frames.
|
|
58
|
+
- **Observation modes**: Geocentric, topocentric, heliocentric, barycentric.
|
|
59
|
+
- **Velocities**: Full 6-component state vectors (position + velocity).
|
|
60
|
+
- **House systems (19)**: Placidus, Koch, Regiomontanus, Campanus, Equal, Whole Sign, Porphyry, Alcabitius, Polich/Page (Topocentric), Morinus, Meridian, Vehlow, Horizontal, Carter, Krusinski, Natural Gradient, and more.
|
|
61
|
+
- **Sidereal zodiac (43 ayanamshas)**: Fagan/Bradley, Lahiri, Raman, Krishnamurti, star-based and historical variants.
|
|
62
|
+
- **Extended points**: Lunar nodes, Lilith (mean and true), major asteroids (Chiron, Pholus, Ceres, Pallas, Juno, Vesta), TNOs (Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris, Sedna), major fixed stars and Arabic parts.
|
|
63
|
+
- **Event finding**: Sun/Moon longitude crossings (e.g. ingress), with additional events planned (eclipses, etc.).
|
|
64
|
+
- **Swiss Ephemeris compatibility**: Same function names, flags and result structure as `pyswisseph` in most common use cases.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
Using `pip`:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install libephemeris
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Using [`uv`](https://github.com/astral-sh/uv) (recommended for development):
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uv pip install libephemeris
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
From source:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
git clone https://github.com/g-battaglia/libephemeris.git
|
|
86
|
+
cd libephemeris
|
|
87
|
+
uv pip install -e .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Requirements
|
|
91
|
+
|
|
92
|
+
- Python **3.10+**
|
|
93
|
+
- `skyfield>=1.53`
|
|
94
|
+
- `skyfield-data>=7.0.0`
|
|
95
|
+
- A JPL ephemeris file (DE421 by default, downloaded automatically on first use if not present locally)
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Quick Start
|
|
100
|
+
|
|
101
|
+
### Basic planetary positions
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import libephemeris as ephem
|
|
105
|
+
from libephemeris.constants import *
|
|
106
|
+
|
|
107
|
+
# Julian Day (J2000.0)
|
|
108
|
+
jd = ephem.swe_julday(2000, 1, 1, 12.0)
|
|
109
|
+
|
|
110
|
+
# Sun position (longitude, latitude, distance, and speeds)
|
|
111
|
+
sun, flags = ephem.swe_calc_ut(jd, SE_SUN, SEFLG_SWIEPH | SEFLG_SPEED)
|
|
112
|
+
print(f"Sun longitude: {sun[0]:.6f}°")
|
|
113
|
+
print(f"Sun speed: {sun[3]:.6f}°/day")
|
|
114
|
+
|
|
115
|
+
# Moon position
|
|
116
|
+
moon, _ = ephem.swe_calc_ut(jd, SE_MOON, SEFLG_SWIEPH)
|
|
117
|
+
print(f"Moon longitude: {moon[0]:.6f}°")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Houses and angles
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
# Rome coordinates
|
|
124
|
+
lat, lon, alt = 41.9028, 12.4964, 0.0
|
|
125
|
+
jd = ephem.swe_julday(2024, 11, 5, 18.0)
|
|
126
|
+
|
|
127
|
+
# Placidus houses
|
|
128
|
+
cusps, ascmc = ephem.swe_houses(jd, lat, lon, b"P")
|
|
129
|
+
|
|
130
|
+
print(f"Ascendant: {ascmc[0]:.2f}°")
|
|
131
|
+
print(f"MC: {ascmc[1]:.2f}°")
|
|
132
|
+
print(f"House 1: {cusps[1]:.2f}°")
|
|
133
|
+
print(f"House 10: {cusps[10]:.2f}°")
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Sidereal calculations
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
# Lahiri ayanamsha
|
|
140
|
+
ephem.swe_set_sid_mode(SE_SIDM_LAHIRI)
|
|
141
|
+
|
|
142
|
+
ayanamsha = ephem.swe_get_ayanamsa_ut(jd)
|
|
143
|
+
print(f"Lahiri ayanamsha: {ayanamsha:.6f}°")
|
|
144
|
+
|
|
145
|
+
sun_sid, _ = ephem.swe_calc_ut(jd, SE_SUN, SEFLG_SWIEPH | SEFLG_SIDEREAL)
|
|
146
|
+
print(f"Sidereal Sun: {sun_sid[0]:.6f}°")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Longitude crossings
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
# Next time the Sun enters 0° Aries
|
|
153
|
+
next_cross = ephem.swe_solcross_ut(0.0, jd, SEFLG_SWIEPH)
|
|
154
|
+
print(f"Next Aries ingress (JD): {next_cross:.6f}")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Configuring Ephemeris Files
|
|
160
|
+
|
|
161
|
+
By default, LibEphemeris uses the **JPL DE421** kernel (`de421.bsp`), which covers roughly **1900–2050**. The file is:
|
|
162
|
+
|
|
163
|
+
- loaded from a local path if already present, or
|
|
164
|
+
- automatically downloaded via Skyfield the first time it is needed.
|
|
165
|
+
|
|
166
|
+
You can control which ephemeris file is used and where it is loaded from.
|
|
167
|
+
|
|
168
|
+
### Choosing a different JPL kernel
|
|
169
|
+
|
|
170
|
+
Use `set_ephemeris_file()` to select a different `.bsp` file:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from libephemeris import set_ephemeris_file
|
|
174
|
+
|
|
175
|
+
set_ephemeris_file("de431.bsp") # very long time span, larger file
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Supported JPL kernels include, for example:
|
|
179
|
+
|
|
180
|
+
- `de421.bsp`: 1900–2050 (default, ~16 MB)
|
|
181
|
+
- `de422.bsp`: −3000–3000 (~623 MB)
|
|
182
|
+
- `de430.bsp`: 1550–2650 (~128 MB)
|
|
183
|
+
- `de431.bsp`: −13200–17191 (~3.4 GB)
|
|
184
|
+
|
|
185
|
+
If the chosen file is not present locally, Skyfield will attempt to download it.
|
|
186
|
+
|
|
187
|
+
### Custom ephemeris directory
|
|
188
|
+
|
|
189
|
+
Use `set_ephe_path()` to point LibEphemeris to a directory containing JPL kernels:
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
from libephemeris import set_ephe_path
|
|
193
|
+
|
|
194
|
+
set_ephe_path("/path/to/jpl-kernels")
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Resolution order for the ephemeris file is:
|
|
198
|
+
|
|
199
|
+
1. The directory set via `set_ephe_path()`, if any.
|
|
200
|
+
2. The project/workspace root.
|
|
201
|
+
3. Download via Skyfield.
|
|
202
|
+
|
|
203
|
+
If you try to compute positions outside the date range covered by the selected kernel, LibEphemeris will raise an exception describing the supported range.
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## Scientific Accuracy and Validation
|
|
208
|
+
|
|
209
|
+
### Ephemeris data
|
|
210
|
+
|
|
211
|
+
- **Source**: NASA JPL DE ephemerides (DE421 by default).
|
|
212
|
+
- **Time span**: 1900–2050 for DE421; extendable by selecting other kernels.
|
|
213
|
+
- **Precision**: Sub-arcsecond accuracy for major planets within the supported range.
|
|
214
|
+
- **Reference frame**: ICRS/J2000.0.
|
|
215
|
+
|
|
216
|
+
### Comparison with Swiss Ephemeris
|
|
217
|
+
|
|
218
|
+
LibEphemeris has been tested against Swiss Ephemeris using an automated test suite.
|
|
219
|
+
|
|
220
|
+
| Component | Tests | Pass Rate | Max Difference |
|
|
221
|
+
| ----------------------- | ----- | --------- | -------------- |
|
|
222
|
+
| Planetary positions | 229 | 100% | < 0.001° |
|
|
223
|
+
| House systems | 113 | 100% | < 0.001° |
|
|
224
|
+
| Ayanamsha values | 129 | 100% | < 0.06° |
|
|
225
|
+
| Lunar nodes / Lilith | 40+ | 100% | < 0.01° |
|
|
226
|
+
| Velocities | 100 | 100% | < 0.01°/day |
|
|
227
|
+
|
|
228
|
+
These comparisons are implemented in the `tests/` and `compare_scripts/` directories, and are run regularly during development.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Swiss Ephemeris Compatibility
|
|
233
|
+
|
|
234
|
+
LibEphemeris aims to behave as a **drop-in replacement** for `pyswisseph` in many scenarios:
|
|
235
|
+
|
|
236
|
+
- Same function names (e.g. `swe_calc_ut`, `swe_houses`, `swe_julday`, `swe_revjul`, `swe_get_ayanamsa_ut`).
|
|
237
|
+
- Same integer constants and flags from `libephemeris.constants` (e.g. `SE_SUN`, `SEFLG_SWIEPH`, `SEFLG_SPEED`, `SE_SIDM_LAHIRI`).
|
|
238
|
+
- Similar return types and value ordering.
|
|
239
|
+
|
|
240
|
+
There are still differences and missing features compared to the full Swiss Ephemeris API, especially around:
|
|
241
|
+
|
|
242
|
+
- very long time ranges (beyond the chosen JPL kernel),
|
|
243
|
+
- eclipse and occultation functions,
|
|
244
|
+
- the full minor-planet and fixed-star catalogues.
|
|
245
|
+
|
|
246
|
+
Please open an issue if you hit a compatibility gap that is important for your use case.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Development
|
|
251
|
+
|
|
252
|
+
### Project layout
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
libephemeris/
|
|
256
|
+
├── libephemeris/
|
|
257
|
+
│ ├── __init__.py
|
|
258
|
+
│ ├── constants.py # Constants and flags
|
|
259
|
+
│ ├── planets.py # Planetary calculations
|
|
260
|
+
│ ├── houses.py # House systems
|
|
261
|
+
│ ├── lunar.py # Nodes and Lilith
|
|
262
|
+
│ ├── minor_bodies.py # Asteroids and TNOs
|
|
263
|
+
│ ├── fixed_stars.py # Fixed stars and points
|
|
264
|
+
│ ├── crossing.py # Longitude crossing events
|
|
265
|
+
│ ├── angles.py # Angle helpers (Asc, MC, etc.)
|
|
266
|
+
│ ├── arabic_parts.py # Arabic parts calculations
|
|
267
|
+
│ ├── time_utils.py # Time conversion helpers
|
|
268
|
+
│ └── state.py # Global state (loader, ephemeris, sidereal mode)
|
|
269
|
+
├── tests/ # Comprehensive test suite
|
|
270
|
+
├── compare_scripts/ # Swiss Ephemeris comparison tools
|
|
271
|
+
└── README.md
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Development workflow
|
|
275
|
+
|
|
276
|
+
Install in editable mode with development dependencies:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
uv pip install -e ".[dev]"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Run tests (via `poethepoet` tasks defined in `pyproject.toml`):
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
poe test # run pytest
|
|
286
|
+
poe coverage # run tests with coverage
|
|
287
|
+
poe lint # run Ruff (lint)
|
|
288
|
+
poe format # run Ruff formatter
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## License
|
|
294
|
+
|
|
295
|
+
LibEphemeris is licensed under the **GNU Lesser General Public License v3.0 (LGPL-3.0)**.
|
|
296
|
+
|
|
297
|
+
See `LICENSE` for the full text.
|
|
298
|
+
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
Built for the astronomical and astrological communities.
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# LibEphemeris
|
|
2
|
+
|
|
3
|
+
**High-precision astronomical ephemeris library for Python (Swiss Ephemeris compatible, powered by Skyfield and JPL DE ephemerides).**
|
|
4
|
+
|
|
5
|
+
> [!WARNING]
|
|
6
|
+
> **Pre-Alpha Release**
|
|
7
|
+
>
|
|
8
|
+
> LibEphemeris is currently in an early pre-alpha stage. The public API is unstable and may change without notice. Do not rely on it in production yet.
|
|
9
|
+
|
|
10
|
+
LibEphemeris is an open-source alternative to Swiss Ephemeris that provides scientific-grade astronomical calculations using NASA JPL ephemerides via [Skyfield](https://rhodesmill.org/skyfield/). The goal is to mirror the Swiss Ephemeris API (as exposed by `pyswisseph`) while using modern, freely available data and a pure-Python implementation.
|
|
11
|
+
|
|
12
|
+
[](https://www.gnu.org/licenses/lgpl-3.0)
|
|
13
|
+
[](https://www.python.org)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Features at a Glance
|
|
18
|
+
|
|
19
|
+
- **Planetary positions**: Sun, Moon, all major planets and Pluto.
|
|
20
|
+
- **High precision**: Based on NASA JPL DE421 by default (configurable to other DE files).
|
|
21
|
+
- **Multiple coordinate systems**: Ecliptic, equatorial, J2000 and of-date frames.
|
|
22
|
+
- **Observation modes**: Geocentric, topocentric, heliocentric, barycentric.
|
|
23
|
+
- **Velocities**: Full 6-component state vectors (position + velocity).
|
|
24
|
+
- **House systems (19)**: Placidus, Koch, Regiomontanus, Campanus, Equal, Whole Sign, Porphyry, Alcabitius, Polich/Page (Topocentric), Morinus, Meridian, Vehlow, Horizontal, Carter, Krusinski, Natural Gradient, and more.
|
|
25
|
+
- **Sidereal zodiac (43 ayanamshas)**: Fagan/Bradley, Lahiri, Raman, Krishnamurti, star-based and historical variants.
|
|
26
|
+
- **Extended points**: Lunar nodes, Lilith (mean and true), major asteroids (Chiron, Pholus, Ceres, Pallas, Juno, Vesta), TNOs (Orcus, Haumea, Quaoar, Makemake, Gonggong, Eris, Sedna), major fixed stars and Arabic parts.
|
|
27
|
+
- **Event finding**: Sun/Moon longitude crossings (e.g. ingress), with additional events planned (eclipses, etc.).
|
|
28
|
+
- **Swiss Ephemeris compatibility**: Same function names, flags and result structure as `pyswisseph` in most common use cases.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
Using `pip`:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install libephemeris
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Using [`uv`](https://github.com/astral-sh/uv) (recommended for development):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv pip install libephemeris
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
From source:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
git clone https://github.com/g-battaglia/libephemeris.git
|
|
50
|
+
cd libephemeris
|
|
51
|
+
uv pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Requirements
|
|
55
|
+
|
|
56
|
+
- Python **3.10+**
|
|
57
|
+
- `skyfield>=1.53`
|
|
58
|
+
- `skyfield-data>=7.0.0`
|
|
59
|
+
- A JPL ephemeris file (DE421 by default, downloaded automatically on first use if not present locally)
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
### Basic planetary positions
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
import libephemeris as ephem
|
|
69
|
+
from libephemeris.constants import *
|
|
70
|
+
|
|
71
|
+
# Julian Day (J2000.0)
|
|
72
|
+
jd = ephem.swe_julday(2000, 1, 1, 12.0)
|
|
73
|
+
|
|
74
|
+
# Sun position (longitude, latitude, distance, and speeds)
|
|
75
|
+
sun, flags = ephem.swe_calc_ut(jd, SE_SUN, SEFLG_SWIEPH | SEFLG_SPEED)
|
|
76
|
+
print(f"Sun longitude: {sun[0]:.6f}°")
|
|
77
|
+
print(f"Sun speed: {sun[3]:.6f}°/day")
|
|
78
|
+
|
|
79
|
+
# Moon position
|
|
80
|
+
moon, _ = ephem.swe_calc_ut(jd, SE_MOON, SEFLG_SWIEPH)
|
|
81
|
+
print(f"Moon longitude: {moon[0]:.6f}°")
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Houses and angles
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# Rome coordinates
|
|
88
|
+
lat, lon, alt = 41.9028, 12.4964, 0.0
|
|
89
|
+
jd = ephem.swe_julday(2024, 11, 5, 18.0)
|
|
90
|
+
|
|
91
|
+
# Placidus houses
|
|
92
|
+
cusps, ascmc = ephem.swe_houses(jd, lat, lon, b"P")
|
|
93
|
+
|
|
94
|
+
print(f"Ascendant: {ascmc[0]:.2f}°")
|
|
95
|
+
print(f"MC: {ascmc[1]:.2f}°")
|
|
96
|
+
print(f"House 1: {cusps[1]:.2f}°")
|
|
97
|
+
print(f"House 10: {cusps[10]:.2f}°")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Sidereal calculations
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Lahiri ayanamsha
|
|
104
|
+
ephem.swe_set_sid_mode(SE_SIDM_LAHIRI)
|
|
105
|
+
|
|
106
|
+
ayanamsha = ephem.swe_get_ayanamsa_ut(jd)
|
|
107
|
+
print(f"Lahiri ayanamsha: {ayanamsha:.6f}°")
|
|
108
|
+
|
|
109
|
+
sun_sid, _ = ephem.swe_calc_ut(jd, SE_SUN, SEFLG_SWIEPH | SEFLG_SIDEREAL)
|
|
110
|
+
print(f"Sidereal Sun: {sun_sid[0]:.6f}°")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Longitude crossings
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
# Next time the Sun enters 0° Aries
|
|
117
|
+
next_cross = ephem.swe_solcross_ut(0.0, jd, SEFLG_SWIEPH)
|
|
118
|
+
print(f"Next Aries ingress (JD): {next_cross:.6f}")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Configuring Ephemeris Files
|
|
124
|
+
|
|
125
|
+
By default, LibEphemeris uses the **JPL DE421** kernel (`de421.bsp`), which covers roughly **1900–2050**. The file is:
|
|
126
|
+
|
|
127
|
+
- loaded from a local path if already present, or
|
|
128
|
+
- automatically downloaded via Skyfield the first time it is needed.
|
|
129
|
+
|
|
130
|
+
You can control which ephemeris file is used and where it is loaded from.
|
|
131
|
+
|
|
132
|
+
### Choosing a different JPL kernel
|
|
133
|
+
|
|
134
|
+
Use `set_ephemeris_file()` to select a different `.bsp` file:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from libephemeris import set_ephemeris_file
|
|
138
|
+
|
|
139
|
+
set_ephemeris_file("de431.bsp") # very long time span, larger file
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Supported JPL kernels include, for example:
|
|
143
|
+
|
|
144
|
+
- `de421.bsp`: 1900–2050 (default, ~16 MB)
|
|
145
|
+
- `de422.bsp`: −3000–3000 (~623 MB)
|
|
146
|
+
- `de430.bsp`: 1550–2650 (~128 MB)
|
|
147
|
+
- `de431.bsp`: −13200–17191 (~3.4 GB)
|
|
148
|
+
|
|
149
|
+
If the chosen file is not present locally, Skyfield will attempt to download it.
|
|
150
|
+
|
|
151
|
+
### Custom ephemeris directory
|
|
152
|
+
|
|
153
|
+
Use `set_ephe_path()` to point LibEphemeris to a directory containing JPL kernels:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from libephemeris import set_ephe_path
|
|
157
|
+
|
|
158
|
+
set_ephe_path("/path/to/jpl-kernels")
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Resolution order for the ephemeris file is:
|
|
162
|
+
|
|
163
|
+
1. The directory set via `set_ephe_path()`, if any.
|
|
164
|
+
2. The project/workspace root.
|
|
165
|
+
3. Download via Skyfield.
|
|
166
|
+
|
|
167
|
+
If you try to compute positions outside the date range covered by the selected kernel, LibEphemeris will raise an exception describing the supported range.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Scientific Accuracy and Validation
|
|
172
|
+
|
|
173
|
+
### Ephemeris data
|
|
174
|
+
|
|
175
|
+
- **Source**: NASA JPL DE ephemerides (DE421 by default).
|
|
176
|
+
- **Time span**: 1900–2050 for DE421; extendable by selecting other kernels.
|
|
177
|
+
- **Precision**: Sub-arcsecond accuracy for major planets within the supported range.
|
|
178
|
+
- **Reference frame**: ICRS/J2000.0.
|
|
179
|
+
|
|
180
|
+
### Comparison with Swiss Ephemeris
|
|
181
|
+
|
|
182
|
+
LibEphemeris has been tested against Swiss Ephemeris using an automated test suite.
|
|
183
|
+
|
|
184
|
+
| Component | Tests | Pass Rate | Max Difference |
|
|
185
|
+
| ----------------------- | ----- | --------- | -------------- |
|
|
186
|
+
| Planetary positions | 229 | 100% | < 0.001° |
|
|
187
|
+
| House systems | 113 | 100% | < 0.001° |
|
|
188
|
+
| Ayanamsha values | 129 | 100% | < 0.06° |
|
|
189
|
+
| Lunar nodes / Lilith | 40+ | 100% | < 0.01° |
|
|
190
|
+
| Velocities | 100 | 100% | < 0.01°/day |
|
|
191
|
+
|
|
192
|
+
These comparisons are implemented in the `tests/` and `compare_scripts/` directories, and are run regularly during development.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Swiss Ephemeris Compatibility
|
|
197
|
+
|
|
198
|
+
LibEphemeris aims to behave as a **drop-in replacement** for `pyswisseph` in many scenarios:
|
|
199
|
+
|
|
200
|
+
- Same function names (e.g. `swe_calc_ut`, `swe_houses`, `swe_julday`, `swe_revjul`, `swe_get_ayanamsa_ut`).
|
|
201
|
+
- Same integer constants and flags from `libephemeris.constants` (e.g. `SE_SUN`, `SEFLG_SWIEPH`, `SEFLG_SPEED`, `SE_SIDM_LAHIRI`).
|
|
202
|
+
- Similar return types and value ordering.
|
|
203
|
+
|
|
204
|
+
There are still differences and missing features compared to the full Swiss Ephemeris API, especially around:
|
|
205
|
+
|
|
206
|
+
- very long time ranges (beyond the chosen JPL kernel),
|
|
207
|
+
- eclipse and occultation functions,
|
|
208
|
+
- the full minor-planet and fixed-star catalogues.
|
|
209
|
+
|
|
210
|
+
Please open an issue if you hit a compatibility gap that is important for your use case.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Development
|
|
215
|
+
|
|
216
|
+
### Project layout
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
libephemeris/
|
|
220
|
+
├── libephemeris/
|
|
221
|
+
│ ├── __init__.py
|
|
222
|
+
│ ├── constants.py # Constants and flags
|
|
223
|
+
│ ├── planets.py # Planetary calculations
|
|
224
|
+
│ ├── houses.py # House systems
|
|
225
|
+
│ ├── lunar.py # Nodes and Lilith
|
|
226
|
+
│ ├── minor_bodies.py # Asteroids and TNOs
|
|
227
|
+
│ ├── fixed_stars.py # Fixed stars and points
|
|
228
|
+
│ ├── crossing.py # Longitude crossing events
|
|
229
|
+
│ ├── angles.py # Angle helpers (Asc, MC, etc.)
|
|
230
|
+
│ ├── arabic_parts.py # Arabic parts calculations
|
|
231
|
+
│ ├── time_utils.py # Time conversion helpers
|
|
232
|
+
│ └── state.py # Global state (loader, ephemeris, sidereal mode)
|
|
233
|
+
├── tests/ # Comprehensive test suite
|
|
234
|
+
├── compare_scripts/ # Swiss Ephemeris comparison tools
|
|
235
|
+
└── README.md
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Development workflow
|
|
239
|
+
|
|
240
|
+
Install in editable mode with development dependencies:
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
uv pip install -e ".[dev]"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Run tests (via `poethepoet` tasks defined in `pyproject.toml`):
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
poe test # run pytest
|
|
250
|
+
poe coverage # run tests with coverage
|
|
251
|
+
poe lint # run Ruff (lint)
|
|
252
|
+
poe format # run Ruff formatter
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## License
|
|
258
|
+
|
|
259
|
+
LibEphemeris is licensed under the **GNU Lesser General Public License v3.0 (LGPL-3.0)**.
|
|
260
|
+
|
|
261
|
+
See `LICENSE` for the full text.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
Built for the astronomical and astrological communities.
|
|
@@ -5,12 +5,17 @@ from .planets import (
|
|
|
5
5
|
swe_calc,
|
|
6
6
|
swe_get_ayanamsa_ut,
|
|
7
7
|
swe_get_ayanamsa,
|
|
8
|
+
swe_get_ayanamsa_name,
|
|
8
9
|
swe_set_sid_mode,
|
|
9
10
|
)
|
|
10
11
|
from .houses import swe_houses, swe_houses_ex, swe_house_name
|
|
11
|
-
from .state import
|
|
12
|
+
from .state import (
|
|
13
|
+
set_topo as swe_set_topo,
|
|
14
|
+
set_ephe_path as swe_set_ephe_path,
|
|
15
|
+
set_ephemeris_file as swe_set_ephemeris_file,
|
|
16
|
+
)
|
|
12
17
|
from .crossing import swe_solcross_ut, swe_mooncross_ut, swe_cross_ut
|
|
13
|
-
from .utils import difdeg2n
|
|
18
|
+
from .utils import difdeg2n, swe_calc_angles
|
|
14
19
|
from .fixed_stars import swe_fixstar_ut
|
|
15
20
|
|
|
16
21
|
# =============================================================================
|
|
@@ -36,11 +41,13 @@ house_name = swe_house_name
|
|
|
36
41
|
# Ayanamsa (sidereal)
|
|
37
42
|
get_ayanamsa_ut = swe_get_ayanamsa_ut
|
|
38
43
|
get_ayanamsa = swe_get_ayanamsa
|
|
44
|
+
get_ayanamsa_name = swe_get_ayanamsa_name
|
|
39
45
|
set_sid_mode = swe_set_sid_mode
|
|
40
46
|
|
|
41
47
|
# Observer location
|
|
42
48
|
set_topo = swe_set_topo
|
|
43
49
|
set_ephe_path = swe_set_ephe_path
|
|
50
|
+
set_ephemeris_file = swe_set_ephemeris_file
|
|
44
51
|
|
|
45
52
|
# Fixed Stars
|
|
46
53
|
fixstar_ut = swe_fixstar_ut
|
|
@@ -50,46 +57,7 @@ solcross_ut = swe_solcross_ut
|
|
|
50
57
|
mooncross_ut = swe_mooncross_ut
|
|
51
58
|
|
|
52
59
|
|
|
53
|
-
# Helper function to pre-calculate positions for Arabic parts
|
|
54
|
-
def swe_calc_angles(jd_ut: float, lat: float, lon: float):
|
|
55
|
-
"""
|
|
56
|
-
Pre-calculate and cache astrological angles and planet positions
|
|
57
|
-
for use with Arabic parts.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
jd_ut: Julian Day (UT)
|
|
61
|
-
lat: Latitude (degrees)
|
|
62
|
-
lon: Longitude (degrees)
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
Dictionary with calculated positions
|
|
66
|
-
"""
|
|
67
|
-
from .state import set_angles_cache
|
|
68
|
-
from .angles import calc_angles
|
|
69
60
|
|
|
70
|
-
# Set observer location
|
|
71
|
-
swe_set_topo(lon, lat, 0)
|
|
72
|
-
|
|
73
|
-
# Calculate angles
|
|
74
|
-
angles_dict = calc_angles(jd_ut, lat, lon)
|
|
75
|
-
|
|
76
|
-
# Calculate and add planet positions for Arabic parts
|
|
77
|
-
from .constants import SE_SUN, SE_MOON, SE_MERCURY, SE_VENUS
|
|
78
|
-
|
|
79
|
-
sun_pos, _ = swe_calc_ut(jd_ut, SE_SUN, 0)
|
|
80
|
-
moon_pos, _ = swe_calc_ut(jd_ut, SE_MOON, 0)
|
|
81
|
-
mercury_pos, _ = swe_calc_ut(jd_ut, SE_MERCURY, 0)
|
|
82
|
-
venus_pos, _ = swe_calc_ut(jd_ut, SE_VENUS, 0)
|
|
83
|
-
|
|
84
|
-
angles_dict['Sun'] = sun_pos[0]
|
|
85
|
-
angles_dict['Moon'] = moon_pos[0]
|
|
86
|
-
angles_dict['Mercury'] = mercury_pos[0]
|
|
87
|
-
angles_dict['Venus'] = venus_pos[0]
|
|
88
|
-
|
|
89
|
-
# Cache for Arabic parts
|
|
90
|
-
set_angles_cache(angles_dict)
|
|
91
|
-
|
|
92
|
-
return angles_dict
|
|
93
61
|
|
|
94
62
|
# Helper for Arabic parts
|
|
95
63
|
from .arabic_parts import calc_all_arabic_parts
|
|
@@ -129,12 +97,17 @@ __all__ = [
|
|
|
129
97
|
"get_ayanamsa_ut",
|
|
130
98
|
"swe_get_ayanamsa",
|
|
131
99
|
"get_ayanamsa",
|
|
100
|
+
"swe_get_ayanamsa",
|
|
101
|
+
"get_ayanamsa",
|
|
132
102
|
"swe_get_ayanamsa_name",
|
|
103
|
+
"get_ayanamsa_name",
|
|
133
104
|
# Observer location
|
|
134
105
|
"swe_set_topo",
|
|
135
106
|
"set_topo",
|
|
136
107
|
"swe_set_ephe_path",
|
|
137
108
|
"set_ephe_path",
|
|
109
|
+
"swe_set_ephemeris_file",
|
|
110
|
+
"set_ephemeris_file",
|
|
138
111
|
# Crossings
|
|
139
112
|
"swe_solcross_ut",
|
|
140
113
|
"solcross_ut",
|
|
@@ -143,6 +116,7 @@ __all__ = [
|
|
|
143
116
|
"swe_cross_ut",
|
|
144
117
|
# Utilities
|
|
145
118
|
"difdeg2n",
|
|
119
|
+
"swe_calc_angles",
|
|
146
120
|
# Helpers
|
|
147
121
|
"calc_all_arabic_parts",
|
|
148
122
|
# Fixed Stars
|