Architecture
This page describes the internal architecture of Ketu v1.3.
Module Structure
ketu/
├── __init__.py # Public re-exports: bodies, aspects, signs, HOUSES_DTYPE,
│ # HighLatitudeError, HOUSE_SYSTEMS, calculate_houses,
│ # house_of, __version__
├── core.py # Fundamental data structures: bodies (14), aspects, signs
├── calculations.py # High-level API: long, lat, dist_au, body_sign,
│ # is_retrograde, positions, body_name, body_properties
├── display.py # CLI display: print_positions, print_aspects, main
├── aspect_windows.py # Aspect timing: AspectMoment, AspectWindow,
│ # find_aspect_window, find_aspects_timeline
├── transits.py # Transit calculations: NatalPosition, TransitAspect,
│ # get_natal_positions, find_transits_to_position
│
├── aspects/ # Configurable aspect sets (New in v1.1)
│ └── __init__.py # CLASSICAL, TRADITIONAL, EXTENDED, AspectSetSpec,
│ # resolve_aspect_set, calculate_aspects, get_aspect, get_orb
│
├── houses/ # House system calculations (New in v1.1/v1.2)
│ └── __init__.py # calculate_houses, house_of, HOUSES_DTYPE, SYSTEMS,
│ # HighLatitudeError, register (6 systems)
│
├── charts/ # Full natal chart (New in v1.2)
│ └── __init__.py # compute_chart, is_day_chart, CHART_DTYPE
│
├── synastry/ # Inter-chart aspects (New in v1.2)
│ └── __init__.py # calculate_synastry, SYNASTRY_DTYPE
│
├── composite/ # Midpoint composite charts (New in v1.2)
│ └── __init__.py # calculate_composite, circular_midpoint
│
├── returns/ # Solar and lunar returns (New in v1.2)
│ └── __init__.py # solar_return, lunar_return
│
├── parts/ # Arabic Parts / Hermetic Lots (New in v1.2)
│ └── __init__.py # PARTS, calculate_part, calculate_all_parts,
│ # register, get_part, PartSpec
│
├── cache/ # High-performance ephemeris cache
│ └── ephemeris_cache.py # Monthly pre-computed positions (O(1) lookups)
│
├── data/ # Embedded coefficient data (New in v1.3)
│ └── chiron_coeffs.npz # Chebyshev polynomial coefficients for Chiron,
│ # 1900–2100, seg=32 days, degree=10
│
└── ephemeris/ # Low-level astronomical calculations (pure NumPy)
├── __init__.py # Ephemeris package API
├── time.py # Time conversions: utc_to_julian, local_to_utc,
│ # sidereal time, Delta T
├── orbital.py # Orbital mechanics: Kepler solver, orbital elements,
│ # perturbations (re-export hub; elements in _elements.py)
├── _elements.py # ORBITAL_ELEMENTS + Lilith constants (extracted in v1.2)
├── _perturbations.py # apply_perturbations strategy (extracted in v1.2)
├── coordinates.py # Coordinate transformations: ecliptic↔equatorial,
│ # heliocentric↔geocentric, nutation, aberration
├── planets.py # Planetary position dispatch: BODY_STRATEGIES dict,
│ # calc_planet_position, get_body_position, body_properties
└── chiron.py # Chiron Chebyshev evaluator (New in v1.3): private helpers
# _load_chiron_data, _chiron_scalar, _chiron_vec
Runtime Dependencies
Ketu is a pure NumPy library at runtime. The only runtime dependency is NumPy.
pyswisseph is used only in the offline build tool (tools/gen_chiron_coeffs.py) to generate the Chiron Chebyshev coefficients. It is never imported at runtime, which maintains AGPL isolation.
Core Components
Data Structures (core.py)
Defines fundamental structured arrays:
bodies: 14-element structured array (name,id,orb,speed). Index 13 = Chiron (New in v1.3).aspects: 14-element array (name,value,coef) for all supported aspect angles.signs: list of 12 zodiac sign names.
Calculations (calculations.py)
High-level API wrapping ephemeris functions with LRU caching:
positions()— all planetary longitudeslong/lat/dist_au()— single-body position componentsbody_sign()— zodiac sign + degree breakdownis_retrograde()— retrograde detectionbody_name()— body ID to string
Aspects (ketu/aspects/)
Configurable aspect detection (New in v1.1):
CLASSICAL / TRADITIONAL / EXTENDED— boolean masks for preset setscalculate_aspects(jdate, l_bodies, aspects=None)— accepts anyAspectSetSpecget_aspect(jdate, body1, body2)— single pairget_orb(body1, body2, asp)— orb for pair + aspect
House Systems (ketu/houses/)
Six house systems (New in v1.1/v1.2):
Placidus, Koch, Porphyry, Whole Sign, Equal, Regiomontanus
calculate_houses(jd, lat, lon, system, polar_fallback)→HOUSES_DTYPEhouse_of(planet_lon, cusps)— vectorised house assignmentregister— extend with custom systemsHighLatitudeError— raised when Placidus/Koch fail near poles
Charts (ketu/charts/)
Full natal chart (New in v1.2):
compute_chart(jd, lat, lon, system, aspects, polar_fallback)→CHART_DTYPEis_day_chart(jd, lat, lon)— sect helper (Sun above horizon)CHART_DTYPE— unified structured array: 14 body positions, 12 cusps, angles, 14×14 aspect matrix
Relational Charts (ketu/synastry/, ketu/composite/)
Inter-chart analysis (New in v1.2):
calculate_synastry(chart_a, chart_b, aspects, orbs, mode)→SYNASTRY_DTYPEcalculate_composite(chart_a, chart_b, system)→CHART_DTYPEcircular_midpoint(lon_a, lon_b)— shortest-arc midpoint utility
Predictive Charts (ketu/returns/)
Solar and lunar returns (New in v1.2):
solar_return(natal_jd, …, target_year)— exact Sun return to natal positionlunar_return(natal_jd, …, target_jd)— next Moon return after target dateBoth return
CHART_DTYPEfor the return chartSupport relocation via
return_lat/return_lonparameters
Arabic Parts (ketu/parts/)
Hermetic Lots (New in v1.2):
PARTSregistry:fortune,spirit,marriagecalculate_part(part_name, chart)— sect-aware for Fortune/Spiritcalculate_all_parts(chart, parts=None)→dict[str, float]Custom parts via
register(name, day_formula, night_formula, description)
Ephemeris Package
Time Conversions (ephemeris/time.py)
UTC ↔ Julian Day conversions
Equation of time calculations
Sidereal time calculations
Delta T corrections for historical dates
Uses purely mathematical formulas — no external dependencies.
Orbital Mechanics (ephemeris/orbital.py)
Re-export hub delegating to:
_elements.py:ORBITAL_ELEMENTS+ Lilith constants (extracted in v1.2 to eliminate circular import risk)_perturbations.py:apply_perturbationsstrategy
Core functions:
Kepler solver (Newton-Raphson)
Position from orbital elements
Major planetary perturbations
Coordinate Transformations (ephemeris/coordinates.py)
Ecliptic ↔ Equatorial coordinates
Heliocentric ↔ Geocentric positions
Rectangular ↔ Spherical coordinates
Nutation + aberration corrections (applied inside body-vec functions)
Planetary Calculations (ephemeris/planets.py)
Strategy-based dispatch (refactored in v1.2):
BODY_STRATEGIES— dict mapping body_id → computation function; Chiron strategy added at index 13 (v1.3)calc_planet_position(jday, body)— dispatches via strategy dictget_body_position / get_body_position_vectorized— scalar and batch entry pointsbody_properties(jd, body)— full 6-component vector (lon, lat, dist, velocities), LRU-cached
Chiron Evaluator (ephemeris/chiron.py)
New in v1.3. Private helpers — not part of the public API:
_load_chiron_data()— loadsketu/data/chiron_coeffs.npzviaimportlib.resources_chiron_scalar(jd)— evaluates Chebyshev polynomial for a single JD_chiron_vec(jd_array)— vectorised batch evaluation
Coefficients: 2283 segments, 32-day width, degree 10, three quantities (lon, lat, dist). Max error: 0.001214° over 1900–2100.
Design Principles
Separation of Concerns
ephemeris/: pure astronomical calculations (no astrological interpretation)calculations.py: astrological interpretation layerdisplay.py: user interface onlySubpackages: each feature area is self-contained
Vectorization First
All core functions support both scalar and array inputs via NumPy broadcasting.
No Global State
All functions are pure — same inputs always produce same outputs. LRU cache is the only shared state (clearable via body_properties.cache_clear()).
Pure NumPy Runtime
Only NumPy is imported at runtime. pyswisseph is a test/build-only dependency (AGPL isolation).
100% Test Coverage
All branches are covered by the test suite (1373+ tests). The fail_under=100 gate is enforced in CI via pytest-cov.
Data Flow
Position Calculation Flow
from ketu.calculations import long
long(jd, body)
|
v
ephemeris/planets.py — body_properties(jd, body)
|
v
BODY_STRATEGIES[body](jd) ← strategy dispatch
|
body < 13: calc_planet_position (orbital mechanics)
body == 13: _chiron_vec / _chiron_scalar (Chebyshev)
|
v
Returns: [lon, lat, dist, lon_speed, lat_speed, dist_speed]
Chart Calculation Flow
from ketu.charts import compute_chart
compute_chart(jd, lat, lon, system)
|
v
1. get_body_position_vectorized → body_lons[14], body_lats[14], body_speeds[14]
2. calculate_houses(jd, lat, lon, system) → cusps[12], asc, mc, armc, vertex
3. calculate_aspects(jd, ...) → aspect_matrix[14,14], aspect_orbs[14,14]
|
v
Returns: scalar CHART_DTYPE array
Testing Strategy
Unit Tests
Individual functions in
ephemeris/Isolated calculations
Edge cases and boundary conditions
Integration Tests
Full chart computation
Aspect detection
Time conversions
Chiron accuracy pins (reference longitudes spanning 1900–2100)
Quality Gates (CI)
pytest: 1373+ tests, all must pass
Coverage: 100% (
fail_under=100, zero pragma,exclude_linesfor proven dead branches)mypy strict: zero errors across all subpackages
numpydoc: all public docstrings validated
doctests: 56+ inline examples verified via
pytest --doctest-modules ketu/