Référence API

L’API de Ketu est organisée en sous-paquets. Toutes les fonctions publiques utilisent des chemins d’import de sous-modules — l’espace de noms ketu de niveau supérieur ne ré-exporte que les éléments listés dans la section « Exports de niveau supérieur » ci-dessous.

Exports de niveau supérieur

import ketu

ketu.bodies          # structured array of celestial bodies
ketu.aspects         # structured array of astrological aspects
ketu.signs           # list of zodiac sign names
ketu.HOUSES_DTYPE    # NumPy dtype for house results
ketu.HighLatitudeError  # exception for polar house failures
ketu.HOUSE_SYSTEMS   # alias for ketu.houses.SYSTEMS
ketu.calculate_houses   # alias for ketu.houses.calculate_houses
ketu.house_of           # alias for ketu.houses.house_of
ketu.__version__        # package version string

Calculs (ketu.calculations)

Fonctions principales de position et d’analyse. Toutes utilisent des numéros de Jour Julien (float).

from ketu.calculations import (
    long,
    lat,
    dist_au,
    body_sign,
    is_retrograde,
    positions,
    body_name,
)

long(jday, body) / lat(jday, body) / dist_au(jday, body)

Retourne la longitude écliptique (degrés), la latitude (degrés) et la distance (UA) d’un corps.

Paramètres :

  • jday (float) : numéro de Jour Julien

  • body (int) : identifiant du corps (0 = Soleil … 13 = Chiron)

Retourne : float

from ketu.calculations import long, lat, dist_au

jd = 2451545.0  # J2000

sun_lon = long(jd, 0)   # Sun longitude
moon_lat = lat(jd, 1)   # Moon latitude
mars_au  = dist_au(jd, 4)  # Mars distance in AU

# Chiron (body_id=13, New in v1.3)
chiron_lon = long(jd, 13)   # e.g. 251.61°
chiron_lat = lat(jd, 13)

positions(jday, l_bodies=bodies)

Retourne un tableau de longitudes pour tous les corps (ou un sous-ensemble).

Retourne : numpy.ndarray de float64, forme (N,)

from ketu.calculations import positions
import ketu

lons = positions(jd, ketu.bodies)

body_sign(b_long)

Détermine le signe du zodiaque et la décomposition en degrés pour une longitude.

Paramètres : b_long (float) : longitude écliptique en degrés

Retourne : numpy.ndarray de int32, champs [sign_index, degrees, minutes, seconds]

from ketu.calculations import long, body_sign
import ketu

moon_lon  = long(jd, 1)
sign_data = body_sign(moon_lon)
print(f"Moon: {ketu.signs[sign_data[0]]} {sign_data[1]}° {sign_data[2]}'")

is_retrograde(jday, body)

Retourne True si le corps a une vitesse longitudinale négative (mouvement rétrograde).

from ketu.calculations import is_retrograde

if is_retrograde(jd, 2):   # Mercury
    print("Mercury retrograde")

is_ascending(jday, body)

Retourne True si la latitude écliptique (β) du corps augmente (vitesse β positive). C’est la fonction de trajectoire β, inchangée depuis v1.0. Elle est distincte de is_ascending_declination — voir Déclinaison équatoriale (Nouveau dans v1.5) pour le piège β-vs-δ.

from ketu.calculations import is_ascending

if is_ascending(jd, 1):   # Moon β rising
    print("Moon ascending in ecliptic latitude")

declination(jdate, body) — Nouveau dans v1.5

Retourne la déclinaison équatoriale δ d’un corps en degrés (nord positif, sud négatif), plage [−90, +90].

Calculée via la chaîne écliptique-vers-équatoriale : spherical_to_rectangular(λ, β, 1) ecliptic_to_equatorial(ε) rectangular_to_spherical — numériquement équivalent à l’éq. 13.4 de Meeus. L’entrée scalaire utilise les fonctions long/lat mises en cache. L’entrée tableau est vectorisée sans boucle via calc_planet_position_batch.

Paramètres :

  • jdate (float ou numpy.ndarray) : numéro de Jour Julien (scalaire ou tableau 1-D)

  • body (int) : identifiant du corps (0 = Soleil … 13 = Chiron)

Retourne : float (scalaire) ou numpy.ndarray (entrée tableau), même forme que jdate

from ketu.calculations import declination
import numpy as np

jd = 2451545.0  # J2000

# Scalar
moon_decl = declination(jd, 1)   # e.g. −23.03°

# Vectorized
jds = np.array([2451545.0, 2451600.0, 2451650.0])
moon_decls = declination(jds, 1)  # shape (3,)

declination_velocity(jdate, body) — Nouveau dans v1.5

Retourne le taux de variation de la déclinaison équatoriale dδ/dt en degrés/jour (positif = vers le nord, négatif = vers le sud).

Calculée par différence finie vers l’avant avec un pas de 0,01 jour, en miroir de l’idiome DF utilisé pour lat_velocity.

Paramètres :

  • jdate (float) : numéro de Jour Julien

  • body (int) : identifiant du corps (0 = Soleil … 13 = Chiron)

Retourne : float

from ketu.calculations import declination_velocity

jd = 2451545.0

moon_vel = declination_velocity(jd, 1)   # e.g. +4.23 °/day

is_ascending_declination(jdate, body) — Nouveau dans v1.5

Retourne True quand dδ/dt > 0 — la Lune (ou tout corps) est montante (se déplaçant vers le nord en déclinaison).

C’est la fonction biodynamique montant/descendant. Elle n’est pas la même que is_ascending, qui suit la latitude écliptique β. Voir Déclinaison équatoriale (Nouveau dans v1.5) pour la distinction explicite β-vs-δ.

Paramètres :

  • jdate (float) : numéro de Jour Julien

  • body (int) : identifiant du corps (0 = Soleil … 13 = Chiron)

Retourne : bool

from ketu.calculations import is_ascending_declination

jd = 2451545.0

if is_ascending_declination(jd, 1):   # Moon montante
    print("Moon montante (northward in declination)")

is_out_of_bounds(jdate, body) — Nouveau dans v1.5

Retourne True quand |δ| > ε(jd) — la déclinaison du corps dépasse l’obliquité vraie instantanée de l’écliptique (hors limites / out-of-bounds).

La Lune peut être hors limites pendant les périodes de grand arrêt lunaire (~18,6 ans cycle nodal ; plus récemment vers 2024–2025, avec |δ| jusqu’à ~28,7°).

Paramètres :

  • jdate (float) : numéro de Jour Julien

  • body (int) : identifiant du corps (0 = Soleil … 13 = Chiron)

Retourne : bool

from ketu.calculations import is_out_of_bounds

jd = 2451545.0

if is_out_of_bounds(jd, 1):   # Moon OOB?
    print("Moon is out of bounds")

body_name(body)

Retourne le nom en chaîne de caractères pour un identifiant de corps.

from ketu.calculations import body_name

print(body_name(0))   # "Sun"
print(body_name(13))  # "Chiron"

Temps (ketu.ephemeris.time)

from ketu.ephemeris.time import utc_to_julian, local_to_utc

utc_to_julian(dtime)

Convertit un datetime UTC en numéro de Jour Julien.

Paramètres : dtime (datetime) : datetime UTC (avec ou sans information de fuseau horaire)

Retourne : float

from ketu.ephemeris.time import utc_to_julian
from datetime import datetime

jd = utc_to_julian(datetime(2000, 1, 1, 12, 0))
# jd == 2451545.0  (J2000.0)

local_to_utc(dtime, zoneinfo=None)

Convertit un datetime local en UTC.

Paramètres :

  • dtime (datetime) : datetime local avec ou sans tzinfo

  • zoneinfo (ZoneInfo, optionnel) : fuseau horaire si non intégré dans dtime

Retourne : datetime en UTC

from ketu.ephemeris.time import local_to_utc, utc_to_julian
from datetime import datetime
from zoneinfo import ZoneInfo

paris = ZoneInfo("Europe/Paris")
dt_local = datetime(2020, 12, 21, 19, 20, tzinfo=paris)
dt_utc = local_to_utc(dt_local)
jd = utc_to_julian(dt_utc)

Aspects (ketu.aspects)

Détection d’aspects configurable. Nouveau en v1.1 : ensembles d’aspects prédéfinis.

from ketu.aspects import (
    get_aspect,
    calculate_aspects,
    get_orb,
    CLASSICAL,
    TRADITIONAL,
    EXTENDED,
    AspectSetSpec,
    resolve_aspect_set,
)

Ensembles d’aspects prédéfinis

Nom

Aspects inclus

Notes

TRADITIONAL

Conjonction, Semi-sextile, Sextile, Carré, Trigone, Quinconce, Opposition (7 aspects)

Défaut de la bibliothèque (v1.3+)

CLASSICAL

Conjonction, Sextile, Carré, Trigone, Opposition (5 aspects)

Défaut de v1.2 et antérieures

EXTENDED

Les 14 aspects

Inclut les mineurs plein-cercle (H5/H9/H10)

Tous les prédéfinis sont des masques booléens numpy.ndarray sur la table des 14 aspects.

AspectSetSpec = Union[str, list, numpy.ndarray, None] — l’un quelconque de ces types peut être passé comme argument aspects à calculate_aspects.

aspects_for_harmonics(harmonics)

Compose un ensemble d’aspects personnalisé à partir d’une liste d’harmoniques. Retourne un masque numpy.bool_ gelé de longueur 14 utilisable comme argument aspects= dans toute fonction Ketu.

Paramètres :

  • harmonics (Sequence[int]) : liste d’entiers harmoniques ; valeurs valides : {1, 2, 3, 5, 6, 9, 10}

Retourne : numpy.ndarray gelé de numpy.bool_, forme (14,)

Lève : ValueError si un harmonique n’est pas dans l’ensemble valide ou n’est pas un entier.

from ketu.aspects import aspects_for_harmonics

# The 7 half-circle aspects (= TRADITIONAL, the library default):
mask = aspects_for_harmonics([1, 2, 3, 6])

# Full-circle minor aspects (H5/H9/H10):
minors = aspects_for_harmonics([5, 9, 10])

# All 14 aspects (= EXTENDED):
all14 = aspects_for_harmonics([1, 2, 3, 5, 6, 9, 10])

# Just Sextile + Trine (harmonic 3, half-circle convention):
h3 = aspects_for_harmonics([3])

# Pass directly to calculate_aspects:
from ketu.aspects import calculate_aspects
result = calculate_aspects(jd, aspects=aspects_for_harmonics([1, 2, 3, 6]))

generate_harmonic_aspects(h)

Génère des spécifications d’aspects à la volée pour tout harmonique entier h — pas uniquement les harmoniques des presets nommés {1, 2, 3, 5, 6, 9, 10}. Pour chaque k = 1 h//2, la fonction calcule angle = fold_to_0_180(k · 360 / h) et coef = k / h, en utilisant la convention plein-cercle 360° repliée sur 0–180°.

Paramètres :

  • h (int) : l’harmonique, 2 h 64. h = 1 est rejeté (dégénéré, 0 lignes) ; h > 64 est rejeté (orbes impraticablement petits).

Retourne : tableau structuré avec le même dtype que core.aspects (substitut direct), forme (h // 2,). Les noms sont auto-générés (b'H7-1', b'H7-2', …). Passe le résultat comme argument dynamic_specs= à calculate_aspects, find_aspects_between_dates et calculate_synastry.

Lève : ValueError si h n’est pas un int ou est en dehors de [2, 64].

from ketu.aspects import generate_harmonic_aspects

# Harmonic 7: 3 unique folded angles (septile family)
specs = generate_harmonic_aspects(7)
print(len(specs))          # 3
print(specs['name'])       # [b'H7-1', b'H7-2', b'H7-3']
print(specs['angle'])      # [51.43, 102.86, 154.29]
print(specs['coef'])       # [0.1429, 0.2857, 0.4286]

# Pass to calculate_aspects via dynamic_specs:
from ketu.aspects import calculate_aspects
result = calculate_aspects(jd, dynamic_specs=generate_harmonic_aspects(7))

Note sur les orbes : Les orbes des harmoniques dynamiques utilisent coef = k / h (convention plein-cercle). Pour les harmoniques élevés, cela donne des orbes environ deux fois plus petits que l’aspect demi-cercle équivalent — comportement accepté ; les deux conventions coexistent sans unification (voir les notes de version v1.4).

Contrat de nommage (v1.5+) : Les octets name émis sont toujours b'H{h}-{k}' (dtype S16), pour k = 1…h//2 en ordre croissant. Ce mapping (h, k) (name, angle, coef) est figé pour toutes les versions mineures et correctives v1.5+ — aucune substitution par un nom traditionnel n’est jamais effectuée par le générateur. Voir Nommage harmonique synthétique (H{h}-{k}) dans Concepts pour l’explication complète des canaux GÉNÉRATEUR vs. DÉTECTION et la table de référence des noms traditionnels.

core.aspects columns: harmonic and symbol

core.aspects est un tableau structuré à 5 champs (name, angle, coef, harmonic, symbol). Nouveau en v1.3 : les colonnes harmonic et symbol.

  • harmonic (int32) : la base harmonique de chaque aspect. Valeurs : [1, 6, 10, 9, 3, 5, 9, 2, 10, 3, 5, 6, 9, 1] pour les aspects 0–13 dans l’ordre canonique de la table. aspects_for_harmonics utilise cette colonne en interne (piloté par les données, sans indices codés en dur).

  • symbol (U4) : glyphe Unicode pour les 7 aspects demi-cercle (☌ ⚺ ⚹ □ △ ⚻ ☍) ; vide ("") pour les 7 aspects mineurs plein-cercle.

  • coef (float32) : coefficient d’orbe. Conceptuellement désigné comme coefficient dans la documentation API ; le nom du champ dans le dtype est coef et n’a pas été renommé en v1.3.

import ketu.core

# Access new columns:
harmonics = ketu.core.aspects["harmonic"]    # array([1, 6, 10, 9, 3, 5, 9, 2, 10, 3, 5, 6, 9, 1])
symbols   = ketu.core.aspects["symbol"]     # ['☌', '⚺', '', '', '⚹', '', '', '□', '', '△', '', '⚻', '', '☍']
coefs     = ketu.core.aspects["coef"]       # orb coefficients (field name: 'coef', not 'coefficient')

get_aspect(jday, body1, body2)

Retourne l’aspect entre deux corps, ou None si aucun aspect dans l’orbe n’existe.

Retourne : tuple[int, int, int, float](body1, body2, aspect_id, orb) ou None

from ketu.aspects import get_aspect

result = get_aspect(jd, 0, 1)   # Sun–Moon
if result:
    b1, b2, asp_id, orb = result
    print(f"aspect_id={asp_id}, orb={orb:.2f}°")

calculate_aspects(jdate, l_bodies=bodies, aspects=None)

Calcule tous les aspects dans l’orbe pour la date donnée.

Paramètres :

  • jdate (float) : Jour Julien

  • l_bodies : sous-ensemble de corps (défaut : tous les corps)

  • aspects (AspectSetSpec, optionnel) : filtre ; None → TRADITIONAL (7 demi-cercle, défaut v1.3+) ; "classical" → CLASSICAL (5) ; "extended" → EXTENDED (14) ; etc.

Retourne : tableau structuré avec les champs (body1, body2, i_asp, orb)

from ketu.aspects import calculate_aspects, CLASSICAL

# Only classical aspects
classical = calculate_aspects(jd, aspects=CLASSICAL)

for row in classical:
    print(row["body1"], row["body2"], row["orb"])

get_orb(body1, body2, asp)

Retourne l’orbe maximum autorisé en degrés pour une paire d’aspects.

find_aspect_timing(jdate, body1, body2, aspect_value, orb=None, dyn_coef=None) — Mis à jour en v1.5

Trouve la fenêtre (début, exact, fin) pour un aspect entre deux corps proche d’une date de référence.

Paramètres :

  • jdate (float) : Jour Julien de référence

  • body1, body2 (int) : identifiants des corps (0 = Soleil … 13 = Chiron)

  • aspect_value (float) : angle d’aspect en degrés

  • orb (float, optionnel) : orbe explicite en degrés — trappe de secours, court-circuite toute résolution interne. Lorsque orb et dyn_coef sont tous deux fournis, orb explicite l’emporte silencieusement (aucune erreur n’est levée).

  • dyn_coef (float, optionnel) : coefficient d’orbe dynamique — nouveau en v1.5 (HARM-04). Lorsque orb vaut None et dyn_coef n’est pas None, l’orbe est dérivé comme (bodies['orb'][body1] + bodies['orb'][body2]) / 2 * dyn_coef, identique à la formule utilisée par calculate_aspects. Passez directement le champ coef d’une ligne generate_harmonic_aspects — aucun précalcul requis.

Résolution de l’orbe — trois branches, vérifiées dans cet ordre :

  1. orb is not None → l’orbe explicite l’emporte immédiatement (même si dyn_coef est aussi fourni).

  2. dyn_coef is not None → orbe dérivé comme (orb_b1 + orb_b2) / 2 * dyn_coef.

  3. Les deux à None → recherche dans la table statique via get_orb(body1, body2, asp_idx). Lève ValueError si aspect_value n’est pas dans la table.

Retourne : tuple[float, float, float](begin_jd, exact_jd, end_jd)

Lève : ValueError lorsque orb et dyn_coef sont tous deux None et aspect_value n’est pas dans la table statique des aspects.

from ketu.aspects.calculator import find_aspect_timing
from ketu.aspects import generate_harmonic_aspects

jd = 2451545.0  # J2000

# Static path — trine (120°) found in the table, orb derived automatically:
begin, exact, end = find_aspect_timing(jd, 0, 1, 120.0)

# Dynamic path — H7-1 Sun-Moon timing via dyn_coef (no pre-computation):
begin, exact, end = find_aspect_timing(jd, 0, 1, 51.4286, dyn_coef=1/7)

# Explicit orb escape hatch (unchanged behaviour):
specs = generate_harmonic_aspects(7)
explicit_orb = (specs["coef"][0]) * 3.0   # custom orb
begin, exact, end = find_aspect_timing(jd, 0, 1, 51.4286, orb=explicit_orb)

Maisons (ketu.houses)

Calculs de systèmes de maisons. Nouveau en v1.1/v1.2.

from ketu.houses import (
    calculate_houses,
    house_of,
    HOUSES_DTYPE,
    SYSTEMS,
    HighLatitudeError,
    register,
)

SYSTEMS

Dictionnaire des systèmes de maisons pris en charge :

SYSTEMS = {
    "placidus", "koch", "porphyry",
    "whole_sign", "equal", "regiomontanus"
}

HOUSES_DTYPE

Dtype NumPy pour les tableaux de résultats de maisons :

jd         float64   Julian Day
lat        float64   geographic latitude (°)
lon        float64   geographic longitude (°)
system     U16       house system name
cusps      float64[12]  twelve house cusp longitudes
asc        float64   Ascendant longitude (°)
mc         float64   Midheaven longitude (°)
armc       float64   ARMC (right ascension of MC, °)
vertex     float64   Vertex longitude (°)

calculate_houses(jd, lat, lon, system="placidus", polar_fallback="raise")

Calcule les cuspides des maisons et les angles pour un moment et un lieu donnés.

Paramètres :

  • jd (float) : Jour Julien

  • lat (float) : latitude géographique en degrés

  • lon (float) : longitude géographique en degrés

  • system (str) : l’une des clés de SYSTEMS

  • polar_fallback (str) : "raise" (défaut) ou un nom de système de repli

Retourne : numpy.ndarray scalaire avec les champs HOUSES_DTYPE

from ketu.houses import calculate_houses

jd = 2451545.0
lat, lon = 48.8566, 2.3522   # Paris

h = calculate_houses(jd, lat, lon, system="placidus")
print(f"ASC: {h['asc']:.2f}°")
print(f"MC:  {h['mc']:.2f}°")
print(f"House 1 cusp: {h['cusps'][0]:.2f}°")

house_of(planet_lon, cusps)

Retourne le numéro de maison (1–12) pour une longitude donnée.

Paramètres :

  • planet_lon (float ou tableau) : longitude écliptique

  • cusps (float[12]) : tableau des cuspides de maisons issu de HOUSES_DTYPE

Retourne : int ou tableau d’int

from ketu.houses import calculate_houses, house_of
from ketu.calculations import long

h = calculate_houses(jd, 48.8566, 2.3522)
sun_lon = long(jd, 0)
print(f"Sun in house {house_of(sun_lon, h['cusps'])}")

HighLatitudeError

Levée par Placidus/Koch quand les cuspides ne peuvent pas être calculées au-delà du cercle polaire. Interceptez-la ou utilisez polar_fallback.

register

Décorateur/fonction pour ajouter un système de maisons personnalisé au registre. Voir Maisons pour un usage avancé.


Thèmes (ketu.charts)

Calcul complet du thème natal. Nouveau en v1.2.

from ketu.charts import compute_chart, is_day_chart, CHART_DTYPE

CHART_DTYPE

Dtype NumPy pour un thème natal complet :

jd              float64      Julian Day
lat             float64      geographic latitude
lon             float64      geographic longitude
system          U16          house system
body_lons       float64[14]  ecliptic longitudes (index 13 = Chiron)
body_lats       float64[14]  ecliptic latitudes
body_speeds     float64[14]  longitudinal velocities (°/day)
cusps           float64[12]  house cusp longitudes
asc             float64      Ascendant
mc              float64      Midheaven
armc            float64      ARMC
vertex          float64      Vertex
aspect_matrix   float64[14,14]  aspect type for each pair (-1 = none)
aspect_orbs     float64[14,14]  orb in degrees for each pair

compute_chart(jd, lat, lon, system="placidus", aspects=None, polar_fallback="raise")

Construit un thème natal complet en un seul tableau structuré.

Paramètres :

  • jd (float) : Jour Julien

  • lat, lon (float) : coordonnées géographiques

  • system (str) : système de maisons

  • aspects (AspectSetSpec) : filtre d’aspects (défaut : TRADITIONAL — les 7 aspects demi-cercle, v1.3+)

  • polar_fallback (str) : repli pour hautes latitudes

Retourne : numpy.ndarray scalaire avec les champs CHART_DTYPE

from ketu.charts import compute_chart

jd = 2451545.0
lat, lon = 48.8566, 2.3522   # Paris

chart = compute_chart(jd, lat, lon, system="placidus")

print(f"ASC:    {chart['asc']:.2f}°")
print(f"Sun:    {chart['body_lons'][0]:.2f}°")
print(f"Moon:   {chart['body_lons'][1]:.2f}°")
print(f"Chiron: {chart['body_lons'][13]:.2f}°")   # body index 13 = Chiron

is_day_chart(jd, lat, lon)

Retourne True si le Soleil est au-dessus de l’horizon au moment et au lieu donnés (utilisé pour les Parts arabes sensibles à la secte).

from ketu.charts import is_day_chart

day = is_day_chart(2451545.0, 48.8566, 2.3522)
print("Day chart" if day else "Night chart")

Voir aussi : Thèmes relationnels


Synastrie (ketu.synastry)

Analyse d’aspects inter-thèmes. Nouveau en v1.2.

from ketu.synastry import calculate_synastry, SYNASTRY_DTYPE

SYNASTRY_DTYPE

body_a       int32     body index in chart A
body_b       int32     body index in chart B
lon_a        float64   longitude in chart A
lon_b        float64   longitude in chart B
aspect_type  int32     aspect index (-1 = none)
orb          float64   orb in degrees
applying     bool      True if applying
orb_limit    float64   maximum allowed orb

calculate_synastry(chart_a, chart_b, aspects="classical", orbs="synastry", mode="filtered")

Calcule tous les aspects inter-thèmes entre deux tableaux CHART_DTYPE.

Paramètres :

  • chart_a, chart_b : tableaux CHART_DTYPE scalaires issus de compute_chart

  • aspects (AspectSetSpec) : filtre d’aspects

  • orbs (str) : ensemble d’orbes ("synastry" applique des orbes réduits)

  • mode (str) : "filtered" retourne uniquement les paires dans l’orbe ; "full" retourne toutes les paires

Retourne : tableau structuré avec les champs SYNASTRY_DTYPE

from ketu.charts import compute_chart
from ketu.synastry import calculate_synastry

chart_a = compute_chart(2451545.0, 48.8566, 2.3522)   # Paris J2000
chart_b = compute_chart(2451910.0, 51.5074, -0.1278)  # London ~1 year later

syn = calculate_synastry(chart_a, chart_b)

for row in syn:
    print(f"A body {row['body_a']} — B body {row['body_b']}: orb {row['orb']:.2f}°")

Voir aussi : Thèmes relationnels


Composite (ketu.composite)

Calcul du thème composite par point médian. Nouveau en v1.2.

from ketu.composite import calculate_composite, circular_midpoint

circular_midpoint(lon_a, lon_b)

Calcule le point médian circulaire (arc le plus court) entre deux longitudes.

Paramètres : lon_a, lon_b (float ou tableau) : longitudes écliptiques en degrés

Retourne : float ou tableau

from ketu.composite import circular_midpoint

mid = circular_midpoint(10.0, 350.0)   # → 0.0° (shortest arc across 0°)

calculate_composite(chart_a, chart_b, system="placidus")

Construit un thème composite (point médian) à partir de deux tableaux CHART_DTYPE natals. Le résultat est un nouveau tableau CHART_DTYPE où chaque position de corps est le point médian circulaire des corps correspondants dans les thèmes A et B.

Retourne : numpy.ndarray scalaire avec les champs CHART_DTYPE

from ketu.charts import compute_chart
from ketu.composite import calculate_composite

chart_a = compute_chart(2451545.0, 48.8566, 2.3522)
chart_b = compute_chart(2451910.0, 48.8566, 2.3522)

composite = calculate_composite(chart_a, chart_b)
print(f"Composite Sun: {composite['body_lons'][0]:.2f}°")

Voir aussi : Thèmes relationnels


Retours (ketu.returns)

Thèmes de retour solaire et lunaire. Nouveau en v1.2.

from ketu.returns import solar_return, lunar_return

Asymétrie clé : solar_return prend target_year comme int ; lunar_return prend target_jd comme float.

solar_return(natal_jd, natal_lat, natal_lon, target_year, return_lat=None, return_lon=None, system="placidus")

Trouve le Jour Julien exact où le Soleil retourne à sa longitude natale pendant target_year, puis construit le thème complet à cet instant.

Paramètres :

  • natal_jd (float) : Jour Julien de naissance

  • natal_lat, natal_lon (float) : coordonnées géographiques de naissance

  • target_year (int) : année grégorienne pour le retour

  • return_lat, return_lon (float, optionnel) : lieu de retour relocalisé ; None → lieu natal

  • system (str) : système de maisons

Retourne : tableau CHART_DTYPE scalaire pour le thème de retour

from ketu.returns import solar_return

natal_jd = 2451545.0
sr = solar_return(natal_jd, 48.8566, 2.3522, target_year=2026)
print(f"Solar Return ASC: {sr['asc']:.2f}°")

lunar_return(natal_jd, natal_lat, natal_lon, target_jd, return_lat=None, return_lon=None, system="placidus")

Trouve le prochain retour lunaire à partir de target_jd (la Lune retourne à sa longitude natale), puis construit le thème.

Paramètres :

  • natal_jd (float) : Jour Julien de naissance

  • natal_lat, natal_lon (float) : coordonnées géographiques de naissance

  • target_jd (float) : la recherche commence à partir de ce Jour Julien

  • return_lat, return_lon (float, optionnel) : lieu relocalisé

  • system (str) : système de maisons

Retourne : tableau CHART_DTYPE scalaire

from ketu.returns import lunar_return
from ketu.ephemeris.time import utc_to_julian
from datetime import datetime

natal_jd = 2451545.0
search_from = utc_to_julian(datetime(2026, 1, 1))

lr = lunar_return(natal_jd, 48.8566, 2.3522, target_jd=search_from)
print(f"Lunar Return Moon: {lr['body_lons'][1]:.2f}°")

Voir aussi : Thèmes prédictifs


Parts arabes (ketu.parts)

Lots hermétiques / Parts arabes. Nouveau en v1.2.

from ketu.parts import (
    PARTS,
    calculate_part,
    calculate_all_parts,
    register,
    get_part,
    PartSpec,
)

PARTS

Dictionnaire de registre associant les noms de parts aux objets PartSpec. Parts intégrées :

Nom

Sensible à la secte

Formule (jour)

"fortune"

Oui

ASC + Lune − Soleil

"spirit"

Oui

ASC + Soleil − Lune

"marriage"

Non (fixe)

ASC + Vénus − Saturne

PartSpec fields: name, day_formula, night_formula, description.

Formula signature: (asc_lon, sun_lon, moon_lon, venus_lon) -> float

calculate_part(part_name, chart)

Calcule la longitude d’une Part arabe nommée pour un thème.

Paramètres :

  • part_name (str) : clé dans le registre PARTS

  • chart : tableau CHART_DTYPE scalaire (doit inclure asc, body_lons)

Retourne : float — longitude écliptique de la Part (degrés)

Fortune et Spirit inversent automatiquement leurs formules pour les thèmes nocturnes (quand le Soleil est sous l’horizon).

from ketu.charts import compute_chart
from ketu.parts import calculate_part

jd = 2451545.0
chart = compute_chart(jd, 48.8566, 2.3522)

fortune = calculate_part("fortune", chart)
spirit  = calculate_part("spirit", chart)
marriage = calculate_part("marriage", chart)

print(f"Part of Fortune: {fortune:.2f}°")
print(f"Part of Spirit:  {spirit:.2f}°")
print(f"Part of Marriage: {marriage:.2f}°")

calculate_all_parts(chart, parts=None)

Calcule toutes les parts enregistrées (ou un sous-ensemble) en une fois.

Paramètres :

  • chart : CHART_DTYPE scalaire

  • parts (list[str], optionnel) : sous-ensemble de clés PARTS ; None → toutes

Retourne : dict[str, float]

from ketu.parts import calculate_all_parts

all_lots = calculate_all_parts(chart)
for name, lon in all_lots.items():
    print(f"{name}: {lon:.2f}°")

register(name, *, day_formula, night_formula, description="")

Ajoute une Part arabe personnalisée au registre.

from ketu.parts import register

def my_formula(asc, sun, moon, venus):
    return (asc + moon - venus) % 360

register("my_part", day_formula=my_formula, night_formula=my_formula, description="Custom part")

get_part(name)

Récupère un PartSpec depuis le registre.

Voir aussi : Parts arabes


Affichage / CLI (ketu.display, ketu.cli)

from ketu.display import print_positions, print_aspects
from ketu.cli import main

main()

Point d’entrée pour la CLI interactive (commande ketu).

parse_harmonics_spec(value) et HarmonicsSelection — Mis à jour en v1.5

parse_harmonics_spec est le validateur argparse type= connecté à l’argument CLI --harmonics. Il retourne un NamedTuple HarmonicsSelection (mask, dynamic_specs).

Champs de HarmonicsSelection :

  • mask (np.ndarray[bool_], forme (14,)) : masque booléen de longueur 14 dans ketu.core.aspects. Tout-False pour les jetons h<N> (seules les specs dynamiques sont utilisées) ; rempli pour les entrées préréglage / liste d’indices.

  • dynamic_specs (DynamicAspectSpec | None) : tableau structuré issu de generate_harmonic_aspects pour les jetons h<N> ; None pour les entrées préréglage et liste d’indices séparés par des virgules.

Formes de spec acceptées :

Forme de spec

Retourne

Notes

"classical" / "traditional" / "extended" / "all"

HarmonicsSelection(mask=<préréglage>, dynamic_specs=None)

"all" est un alias de "extended"

"0,4,7,9,13"

HarmonicsSelection(mask=<calculé>, dynamic_specs=None)

Indices séparés par des virgules dans core.aspects

"h7" / "H7"

HarmonicsSelection(mask=zeros(14), dynamic_specs=<tableau>)

Nouveau en v1.5 — jeton d’harmonique arbitraire h<N>

"h7,h11" / "traditional,h7"

Rejeté (HARMF-01, reporté)

Mélange multi-harmonique pas encore supporté

La forme h<N> (insensible à la casse, N dans [2, 64]) sélectionne uniquement les aspects dynamiques H{N}-{k} via le canal dynamic_specs=. Les entrées préréglage / liste d’indices donnent dynamic_specs=None. Voir --harmonics h7 — harmoniques arbitraires en ligne de commande (Nouveau en v1.5) dans Concepts pour l’usage CLI, la limite de la grammaire stricte, et un exemple pratique.


Déclinaison équatoriale (ketu.calculations) — Nouveau dans v1.5

La déclinaison équatoriale (δ) mesure la distance au nord ou au sud d’un corps par rapport à l’équateur céleste. Elle est distincte de la latitude écliptique (β) :

Grandeur

Symbole

Plan de référence

Fonction Ketu

Latitude écliptique

β

Plan écliptique

lat, is_ascending

Déclinaison équatoriale

δ

Équateur céleste

declination, is_ascending_declination

Piège β-vs-δ — « Lune montante » est ambigu : is_ascending suit la trajectoire β (latitude écliptique croissante) ; is_ascending_declination suit la trajectoire δ (montant/descendant biodynamique). Ces deux fonctions peuvent être en désaccord pour le même corps à la même date. Exemple : au 2025-03-07 (JD=2460742,0, Lune près d’un pic de grand arrêt à δ≈+28,66°), is_ascending_declination=True (δ croissant à +0,30°/jour) tandis que is_ascending=False (β décroissant).

Le cycle δ de la Lune se complète en ≈27,21 jours (mois draconique/nodal). Montante = vers le nord (dδ/dt > 0) ; descendante = vers le sud (dδ/dt < 0). C’est le cycle utilisé en biodynamie (cadrage centré sur les aspects de Loc).

Hors limites (OOB) : la δ de la Lune peut dépasser l’obliquité ε pendant le grand arrêt lunaire (~18,6 ans de cycle nodal). Le seuil utilise l’obliquité vraie instantanée ε(jd), pas l’obliquité moyenne. En 2024–2025, la Lune atteint |δ| ≈ 28,7°.

from ketu.calculations import (
    declination,
    declination_velocity,
    is_ascending_declination,
    is_out_of_bounds,
)

jd = 2451545.0  # J2000

# δ in degrees (north positive, south negative)
moon_decl = declination(jd, 1)
print(f"Moon δ: {moon_decl:.4f}°")

# dδ/dt in °/day
moon_vel = declination_velocity(jd, 1)
print(f"Moon dδ/dt: {moon_vel:.4f}°/day")

# Biodynamic montant/descendant
if is_ascending_declination(jd, 1):
    print("Moon montante (northward)")
else:
    print("Moon descendante (southward)")

# Out-of-bounds check
if is_out_of_bounds(jd, 1):
    print("Moon is out of bounds (|δ| > ε)")

Aspects de déclinaison (ketu.declination) — Nouveau dans v1.6

Sous-paquet additif qui détecte les parallèles et les contre-parallèles sur l’axe de la déclinaison équatoriale. Il consomme chart["body_decl"] (le champ δ signé (14,) livré en v1.5) ; CHART_DTYPE est inchangé. Ces noms sont accessibles uniquement via ketu.declination.* — ils ne sont PAS ré-exportés depuis le niveau supérieur ketu (ketu.__all__ est inchangé, additif seulement).

from ketu.declination import (
    find_declination_aspects,
    declination_aspect_masks,
    DeclinationAspectMasks,
    DECLA_ASPECT_DTYPE,
    DECLA_COEF,
    MIN_DECL_ORB,
)

Voir la page de concepts Aspects de déclinaison pour les définitions sur δ signé, la dérivation de l’orbe à partir des corps et le cadrage biodynamique.

find_declination_aspects(body_decl)

Détecteur scalaire / thème unique.

  • Paramètres : body_decl (ndarray, forme (14,)) — déclinaison δ signée en degrés, c.-à-d. chart["body_decl"].

  • Retourne : ndarray[DECLA_ASPECT_DTYPE] — uniquement les paires du triangle supérieur (body1 < body2), sans doublons, triées par (body1, body2). Retourne np.empty(0, dtype=DECLA_ASPECT_DTYPE) quand rien n’est détecté — jamais None, jamais un tuple.

import numpy as np
from ketu.declination import find_declination_aspects

decl = np.zeros(14)
decl[0] = 20.0   # Sun  δ = +20.0°
decl[1] = 20.5   # Moon δ = +20.5°  → same hemisphere, gap 0.5° ≤ 1.0° orb

aspects = find_declination_aspects(decl)
print(aspects)   # [(0, 1, 'P', 0.5, 1.0)] — Sun/Moon parallel

declination_aspect_masks(body_decl)

Chemin vectorisé par lots. Accepte (S, 14) ou (14,) (promu via np.atleast_2d) et retourne un NamedTuple DeclinationAspectMasks. Diffusion NumPy pure — pas de boucle Python sur les corps.

  • Paramètres : body_decl (ndarray, forme (S, 14) ou (14,)).

  • Retourne : DeclinationAspectMasks.

DeclinationAspectMasks

NamedTuple à six champs, dans l’ordre :

Champ

Forme

Signification

parallel

(S, 91)

masque booléen de parallèle par thème et par paire

contra

(S, 91)

masque booléen de contre-parallèle par thème et par paire

gap

(S, 91)

|δ₁−δ₂| (parallèle) / |δ₁+δ₂| (contre) par thème et par paire

idx_i

(91,)

indice du premier corps de chaque paire

idx_j

(91,)

indice du second corps de chaque paire

orb_pairs

(91,)

limite d’orbe pour chaque paire

91 est le nombre de paires du triangle supérieur pour 14 corps (14 × 13 / 2).

DECLA_ASPECT_DTYPE

Le contrat de ligne figé à 5 champs retourné par find_declination_aspects :

Champ

Type

Signification

body1

i1

indice du premier corps (body1 < body2)

body2

i1

indice du second corps

kind

U2

"P" (parallèle) ou "CP" (contre-parallèle)

gap

f8

|δ₁−δ₂| pour P, |δ₁+δ₂| pour CP

orb

f8

la limite d’orbe utilisée pour cette paire

body1 / body2 sont des i1 (1 octet signé) dans le dtype réel.

DECLA_COEF et MIN_DECL_ORB

  • DECLA_COEF = 1/12 (≈ 0.0833) — mise à l’échelle de l’orbe sur l’axe de la déclinaison.

  • MIN_DECL_ORB = 0.5 — plancher (degrés) pour que les corps à orbe nulle restent détectables.

L’orbe par paire est max((orb_b1 + orb_b2) / 2 × DECLA_COEF, MIN_DECL_ORB) → Soleil/Lune 1.0°, Rahu/Lilith 0.5° (plancher). Voir la page de concepts pour la dérivation complète.


Chiron (body_id=13) — Nouveau en v1.3

Chiron est le 14e corps ajouté en v1.3. Il n’existe pas de module Chiron séparé dans l’API publique — il est accessible via les fonctions de calcul standard en utilisant body_id=13.

Faits clés :

  • ketu.bodies["name"][13] == b"Chiron"

  • Plage de dates valide : 1900–2100 (étendue en v1.4 ; 2283 segments de Chebyshev embarqués dans ketu/data/chiron_coeffs.npz). Toute entrée hors plage est silencieusement clampée à la limite de segment la plus proche.

  • Précision : erreur maximale 0,001214° (sous-arcminute) sur la plage 1900–2100

  • CHART_DTYPE body arrays are 14-wide; index 13 always refers to Chiron

Changement majeur (v1.2 → v1.3) : L’axe de corps CHART_DTYPE a été étendu de 13 à 14 corps (D-08). Le code qui accédait aux corps par un compte fixe ou l’index codé en dur 12 comme dernier corps doit être mis à jour. Voir Migration pour les détails.

from ketu.calculations import long, lat

jd = 2451545.0   # J2000.0

chiron_lon = long(jd, 13)   # e.g. 251.61°
chiron_lat = lat(jd, 13)

print(f"Chiron at J2000: {chiron_lon:.2f}° ecliptic longitude")
from ketu.charts import compute_chart

chart = compute_chart(jd, 48.8566, 2.3522)
chiron_lon = chart["body_lons"][13]   # body axis index 13

Voir aussi : Chiron