Architecture

Cette page décrit l’architecture interne de Ketu v1.3.

Structure des modules

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

Dépendances Runtime

Ketu est une bibliothèque Pure NumPy au runtime. La seule dépendance runtime est NumPy.

pyswisseph est utilisé uniquement dans l’outil de build hors-ligne (tools/gen_chiron_coeffs.py) pour générer les Coefficients de Chebyshev de Chiron. Il n’est jamais importé au runtime, ce qui maintient l’isolation AGPL.

Composants principaux

Structures de données (core.py)

Définit les tableaux structurés fondamentaux :

  • bodies : tableau structuré à 14 éléments (name, id, orb, speed). Index 13 = Chiron (Nouveau en v1.3).

  • aspects : tableau à 14 éléments (name, value, coef) pour tous les angles d’aspects supportés.

  • signs : liste des 12 noms de signes du zodiaque.

Calculs (calculations.py)

API de haut niveau encapsulant les fonctions d’éphéméride avec Cache LRU :

  • positions() — toutes les longitudes planétaires

  • long/lat/dist_au() — composantes de position d’un corps unique

  • body_sign() — signe zodiacal + décomposition en degrés

  • is_retrograde() — détection de rétrogradation

  • body_name() — identifiant de corps vers chaîne de caractères

Aspects (ketu/aspects/)

Détection d’aspects configurable (Nouveau en v1.1) :

  • CLASSICAL / TRADITIONAL / EXTENDED — masques booléens pour les ensembles prédéfinis

  • calculate_aspects(jdate, l_bodies, aspects=None) — accepte tout AspectSetSpec

  • get_aspect(jdate, body1, body2) — paire unique

  • get_orb(body1, body2, asp) — orbe pour la paire + aspect

Systèmes de maisons (ketu/houses/)

Six systèmes de maisons (Nouveau en v1.1/v1.2) :

  • Placidus, Koch, Porphyre, Signe entier, Égal, Regiomontanus

  • calculate_houses(jd, lat, lon, system, polar_fallback)HOUSES_DTYPE

  • house_of(planet_lon, cusps) — affectation de maison vectorisée

  • register — étendre avec des systèmes personnalisés

  • HighLatitudeError — levée lorsque Placidus/Koch échouent près des pôles

Thèmes (ketu/charts/)

Thème natal complet (Nouveau en v1.2) :

  • compute_chart(jd, lat, lon, system, aspects, polar_fallback)CHART_DTYPE

  • is_day_chart(jd, lat, lon) — aide secte (Soleil au-dessus de l’horizon)

  • CHART_DTYPE — tableau structuré unifié : 14 positions de corps, 12 cuspides, angles, matrice d’aspects 14×14

Thèmes relationnels (ketu/synastry/, ketu/composite/)

Analyse inter-thèmes (Nouveau en 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) — utilitaire de point médian par arc minimal

Thèmes prédictifs (ketu/returns/)

Révolutions solaires et lunaires (Nouveau en v1.2) :

  • solar_return(natal_jd, …, target_year) — retour exact du Soleil à la position natale

  • lunar_return(natal_jd, …, target_jd) — prochain retour de la Lune après la date cible

  • Les deux retournent CHART_DTYPE pour le thème de retour

  • Supportent la délocalisation via les paramètres return_lat/return_lon

Parts arabes (ketu/parts/)

Lots hermétiques (Nouveau en v1.2) :

  • Registre PARTS : fortune, spirit, marriage

  • calculate_part(part_name, chart) — sensible à la secte pour Fortune/Spirit

  • calculate_all_parts(chart, parts=None)dict[str, float]

  • Parts personnalisées via register(name, day_formula, night_formula, description)

Package Ephemeris

Conversions de temps (ephemeris/time.py)

  • Conversions UTC ↔ Jour Julien

  • Calculs d’équation du temps

  • Calculs de temps sidéral

  • Corrections Delta T pour les dates historiques

Utilise des formules purement mathématiques — aucune dépendance externe.

Mécanique orbitale (ephemeris/orbital.py)

Hub de ré-export déléguant vers :

  • _elements.py : ORBITAL_ELEMENTS + constantes Lilith (extraites en v1.2 pour éliminer le risque d’import circulaire)

  • _perturbations.py : stratégie apply_perturbations

Fonctions principales :

  • Solveur de Kepler (Newton-Raphson)

  • Position à partir des éléments orbitaux

  • Perturbations planétaires majeures

Transformations de coordonnées (ephemeris/coordinates.py)

  • Coordonnées écliptiques ↔ équatoriales

  • Positions héliocentriques ↔ géocentriques

  • Coordonnées rectangulaires ↔ sphériques

  • Corrections de nutation + aberration (appliquées dans les fonctions body-vec)

Calculs planétaires (ephemeris/planets.py)

Dispatch basé sur la stratégie (refactorisé en v1.2) :

  • BODY_STRATEGIES — dictionnaire associant body_id → fonction de calcul ; stratégie Chiron ajoutée à l’index 13 (v1.3)

  • calc_planet_position(jday, body) — dispatch via le dictionnaire de stratégies

  • get_body_position / get_body_position_vectorized — points d’entrée scalaire et batch

  • body_properties(jd, body) — vecteur complet à 6 composantes (lon, lat, dist, vitesses), mis en Cache LRU

Évaluateur Chiron (ephemeris/chiron.py)

Nouveau en v1.3. Helpers privés — ne font pas partie de l’API publique :

  • _load_chiron_data() — charge ketu/data/chiron_coeffs.npz via importlib.resources

  • _chiron_scalar(jd) — évalue le polynôme de Chebyshev pour un Jour Julien unique

  • _chiron_vec(jd_array) — évaluation batch vectorisée

Coefficients : 2283 segments, largeur 32 jours, degré 10, trois quantités (lon, lat, dist). Erreur max : 0,001214° sur 1900–2100.

Principes de conception

Séparation des préoccupations

  • ephemeris/ : calculs astronomiques purs (sans interprétation astrologique)

  • calculations.py : couche d’interprétation astrologique

  • display.py : interface utilisateur uniquement

  • Sous-paquets : chaque domaine fonctionnel est autonome

Vectorisation en premier

Toutes les fonctions principales supportent entrées scalaires et tableaux via broadcasting NumPy.

Pas d’état global

Toutes les fonctions sont pures — mêmes entrées produisent toujours mêmes sorties. Le Cache LRU est le seul état partagé (effaçable via body_properties.cache_clear()).

Runtime Pure NumPy

Seul NumPy est importé au runtime. pyswisseph est une dépendance test/build uniquement (isolation AGPL).

Couverture de tests à 100%

Toutes les branches sont couvertes par la suite de tests (1373+ tests). La porte fail_under=100 est appliquée en CI via pytest-cov.

Flux de données

Flux de calcul de position

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]

Flux de calcul de thème

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

Stratégie de test

Tests unitaires

  • Fonctions individuelles dans ephemeris/

  • Calculs isolés

  • Cas limites et conditions aux limites

Tests d’intégration

  • Calcul complet de thème

  • Détection d’aspects

  • Conversions de temps

  • Épingles de précision Chiron (longitudes de référence couvrant 1900–2100)

Portes de qualité (CI)

  • pytest : 1373+ tests, tous doivent passer

  • Couverture : 100% (fail_under=100, zéro pragma, exclude_lines pour les branches mortes prouvées)

  • mypy strict : zéro erreur dans tous les sous-paquets

  • numpydoc : toutes les docstrings publiques validées

  • doctests : 56+ exemples inline vérifiés via pytest --doctest-modules ketu/