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 longitudes

  • long/lat/dist_au() — single-body position components

  • body_sign() — zodiac sign + degree breakdown

  • is_retrograde() — retrograde detection

  • body_name() — body ID to string

Aspects (ketu/aspects/)

Configurable aspect detection (New in v1.1):

  • CLASSICAL / TRADITIONAL / EXTENDED — boolean masks for preset sets

  • calculate_aspects(jdate, l_bodies, aspects=None) — accepts any AspectSetSpec

  • get_aspect(jdate, body1, body2) — single pair

  • get_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_DTYPE

  • house_of(planet_lon, cusps) — vectorised house assignment

  • register — extend with custom systems

  • HighLatitudeError — 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_DTYPE

  • is_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_DTYPE

  • calculate_composite(chart_a, chart_b, system)CHART_DTYPE

  • circular_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 position

  • lunar_return(natal_jd, …, target_jd) — next Moon return after target date

  • Both return CHART_DTYPE for the return chart

  • Support relocation via return_lat/return_lon parameters

Arabic Parts (ketu/parts/)

Hermetic Lots (New in v1.2):

  • PARTS registry: fortune, spirit, marriage

  • calculate_part(part_name, chart) — sect-aware for Fortune/Spirit

  • calculate_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_perturbations strategy

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 dict

  • get_body_position / get_body_position_vectorized — scalar and batch entry points

  • body_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() — loads ketu/data/chiron_coeffs.npz via importlib.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 layer

  • display.py: user interface only

  • Subpackages: 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_lines for 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/