API Reference
The admitted Python import surface, public vessels, policy controls, and failure contracts for Moira 6.1.0.
Moira API Reference
Document revision: 2.1.0
Engine baseline: 6.1.0
Last verified: 2026-07-27
Coverage: 13 200 BC → 17 191 AD (JPL DE441)
Import surface: import moira provides the curated stable root, while from moira.facade import ... exposes the complete admitted facade surface.
This is the Python engine/import reference. The HTTP transport surface is
documented separately in wiki/02_services/REST_API_REFERENCE.md.
For the Hellenistic surface, use the generated capability matrix for current export-tier receipts and the source validation audit for evidence qualifications. Those artifacts distinguish admitted engine truth from research-only, closed-exclusion, out-of-contract, and non-Hellenistic branches.
Table of Contents
- Quick Start
- API Architecture — Four-Tier Entry Points
- Core Types
- Moira Facade
- Ephemeris & Positions
- Alternative Reference Frames
- Chart Structure
- Classical Techniques
- Timing Techniques
- Planetary Cycles Engine
- Huber Method
- Relational Techniques
- Geography
- Fixed Stars
- Eclipses & Phenomena
- Harmograms — Spectral Harmonic Analysis
- Constellation Oracle
- Calendar & Time
- Policy Objects
moira.sky— Strict Astronomy APImoira.vedic— Vedic Astrology Surface
Conventions
- Sections labeled
fieldsare intended to be exhaustive for the documented vessel unless explicitly marked otherwise. - Rows or examples that use
...are abbreviated for width only; they are shorthand, not alternate signatures. - When a section says
summary, that label is intentional and means the section is highlighting the most important fields rather than restating every implementation detail inline. - Unless a section explicitly targets
moira.essentials,moira.classical,moira.predictive, or a specialty submodule, direct symbol imports in this reference should be read asfrom moira.facade import ...; the top-levelmoirapackage does not re-export the full low-level surface. - This reference prioritizes callable surfaces, principal vessels, and major policy types.
moira.facade.__all__also includes many public truth/classification/profile dataclasses and enums that are not all restated inline section-by-section.
1. Quick Start
Installation & Kernel
Moira requires an installed JPL planetary kernel before kernel-dependent
computations can run. Moira() auto-detects the first installed planetary
kernel from the supported set de430.bsp, de440.bsp, de441.bsp,
de432.bsp, de431.bsp, searched in this order of locations:
~/.moira/kernels/moira/kernels/inside the installed packagekernels/in a development checkout
The package does not read a MOIRA_KERNEL_PATH environment variable. Large
kernels such as de441.bsp still need to be present locally; use
moira-download-kernels or Moira.download_missing_kernels() to install the
missing files into the user kernel directory.
from moira.facade import Moira
from datetime import datetime, timezone
m = Moira() # auto-detects the first installed planetary kernel
# or
m = Moira(kernel_path="/data/de441.bsp")
First chart
from moira.facade import Moira, Body, HouseSystem
from datetime import datetime, timezone
m = Moira()
dt = datetime(1988, 4, 4, 14, 30, tzinfo=timezone.utc)
chart = m.chart(dt)
for name, planet in chart.planets.items():
print(f"{name:10s} {planet.longitude:.4f}° speed {planet.speed:+.4f}°/day")
houses = m.houses(dt, latitude=51.5074, longitude=-0.1278, system=HouseSystem.PLACIDUS)
print(f"ASC {houses.asc:.3f}° MC {houses.mc:.3f}°")
Aspects
aspects = m.aspects(chart)
for a in aspects:
print(f"{a.body1} {a.aspect} {a.body2} orb {a.orb:+.2f}°")
Transits to natal point
from moira.facade import jd_from_datetime, utc_to_ut1
from datetime import datetime, timezone
natal_sun = chart.planets["Sun"].longitude # e.g. 14.7°
jd_start = utc_to_ut1(jd_from_datetime(datetime(2024, 1, 1, tzinfo=timezone.utc)))
jd_end = utc_to_ut1(jd_from_datetime(datetime(2025, 1, 1, tzinfo=timezone.utc)))
for event in m.transits(Body.JUPITER, natal_sun, jd_start, jd_end):
print(event.jd_ut, event.relation.relation_kind)
2. API Architecture — Four-Tier Entry Points
Moira exposes its admitted public surface through four distinct import points.
The tier modules are cumulative. The root package is intentionally curated,
while moira.facade is the complete admitted facade surface. Deliberately
module-direct research or validation products can remain outside these tiers.
moira.essentials ← Beginner surface: chart, houses, aspects, sidereal
↓
moira.classical ← Adds: dignities, lots, fixed stars, time lords,
profections, Vedic, midpoints, mansions
↓
moira.predictive ← Adds: transits, progressions, synastry, eclipses,
returns, stations, void-of-course, electional
↓
moira.facade ← Complete admitted facade surface
moira ← Curated stable root: Moira, core types, JD/sidereal helpers,
selected visibility, harmogram, orbital, and policy surfaces
moira.essentials — Beginner surface
from moira.essentials import Moira, Chart, Body, HouseSystem
from moira.essentials import PlanetData, SkyPosition, CartesianPosition
from moira.essentials import NodeData, HouseCusps, AspectData
from moira.essentials import CalendarDateTime, DeltaTPolicy
from moira.essentials import julian_day, jd_from_datetime, datetime_from_jd
from moira.essentials import calendar_from_jd, calendar_datetime_from_jd
from moira.essentials import format_jd_utc, safe_datetime_from_jd, delta_t
from moira.essentials import calculate_houses, assign_house
from moira.essentials import find_aspects, AspectPolicy, DEFAULT_POLICY
from moira.essentials import Ayanamsa, ayanamsa, tropical_to_sidereal
from moira.essentials import sidereal_to_tropical, list_ayanamsa_systems
from moira.essentials import DeltaTBreakdown, delta_t_breakdown
Use this when you only need: natal chart positions, house cusps, basic aspects, and sidereal conversions. It is suitable for first-time users and lightweight integrations.
moira.classical — Traditional astrology surface
from moira.classical import * # includes everything from essentials, plus:
Adds the full classical and traditional toolkit:
| Added domain | Key symbols |
|---|---|
| Houses (full) | HouseSystemFamily, HouseSystemCuspBasis, classify_house_system, HousePlacement, HouseBoundaryProfile, HouseAngularity, compare_systems, compare_placements, distribute_points, Quadrant, quadrant_emphasis, DiurnalQuadrant, diurnal_emphasis |
| Aspects (full) | AspectDefinition, ASPECT_TIERS, CANONICAL_ASPECTS, AspectDomain, AspectFamily, AspectTier, MotionState, AspectClassification, HellenisticSuperiorityTruth, hellenistic_superiority_truth, find_whole_sign_aspects, aspect_strength, aspect_motion_state, find_declination_aspects, declination_aspects_from_declinations, declination_aspect_motion_witness, find_patterns |
| Dignities | calculate_dignities, calculate_receptions, EssentialDignityKind, PlanetaryDignity, DignityHorizonFrame, PlanetarySolarPhaseTruth, SolarProximityTruth, BesiegingTruth, planetary_solar_phase_truth, solar_proximity_truth, besieging_truth |
| Arabic Parts | calculate_lots, evaluate_lots, ArabicPart, LotsEvaluation, LotNotEvaluable, ArabicPartsService, list_parts |
| Unified Hellenistic profile | hellenistic_chart_profile, HellenisticChartProfile, HellenisticProfilePolicy, HellenisticProfileProvenance |
| Midpoints | calculate_midpoints, Midpoint, MidpointsService, midpoint_tree, planetary_pictures |
| Antiscia | find_antiscia, AntisciaAspect, antiscion, contra_antiscion |
| Fixed stars | star_at, all_stars_at, FixedStar, list_stars, find_stars, star_magnitude |
| Lunar mansions | mansion_of, all_mansions_at, MANSIONS |
| Profections | annual_profection, monthly_profection, profection_schedule |
| Time lords | firdaria, zodiacal_releasing, vimshottari |
| Vedic divisional | navamsa, saptamsa, dashamansa, dwadashamsa, trimshamsa |
| Vedic dignities | vedic_dignity, planetary_relationships, VedicDignityResult, VedicDignityPolicy |
| Panchanga | panchanga_at, PanchangaResult, PanchangaPolicy, tithi_condition_profile |
| Jaimini | jaimini_karakas, atmakaraka, JaiminiKarakaResult, JaiminiPolicy |
| Ashtakavarga | bhinnashtakavarga, ashtakavarga, AshtakavargaResult, AshtakavargaPolicy |
| Shadbala | shadbala, hora_lord_at, ShadbalaResult, ShadbalaPolicy |
| Alternate dashas | ashtottari, yogini_dasha, AlternateDashaPeriod, AshtottariPolicy, YoginiPolicy |
| Planetary hours | planetary_hours |
| Huber | house_zones, age_point, chart_intensity_profile (also importable directly from moira.huber) |
moira.predictive — Forecasting surface
from moira.predictive import * # includes everything from classical, plus:
Adds the complete forecasting and relationship toolkit:
| Added domain | Key symbols |
|---|---|
| Transits | find_transits, next_transit, find_ingresses, next_ingress, TransitEvent, IngressEvent, TransitSearchPolicy |
| Progressions | secondary_progression, solar_arc, solar_arc_right_ascension, naibod_longitude, tertiary_progression, tertiary_ii_progression, converse_* variants, minor_progression, daily_house_frame |
| Primary directions | speculum, find_primary_arcs, SpeculumEntry, PrimaryArc |
| Synastry | synastry_aspects, house_overlay, mutual_house_overlays, composite_chart, davison_chart, CompositeChart, DavisonChart |
| Eclipses | EclipseData, EclipseEvent, EclipseCalculator, LunarEclipseAnalysis |
| Returns | solar_return, lunar_return, planet_return |
| Stations | find_stations, is_retrograde, retrograde_periods, StationEvent |
| Void of course | void_of_course_window, is_void_of_course, next_void_of_course, void_periods_in_range |
| Phenomena | greatest_elongation, perihelion, aphelion, next_moon_phase, moon_phases_in_range, next_conjunction |
Note:
next_solar_eclipse_at_locationis available frommoira.facadeandmoira.eclipsedirectly but is not re-exported throughmoira.predictive.
moira.facade and moira — Admitted facade vs curated root
import moira # curated stable root, includes Moira and core types
from moira.facade import * # complete admitted facade surface
moira.facade adds every remaining admitted subsystem not exposed by the predictive tier.
The top-level moira package does not mirror the entire facade export list; use
it when you want the primary facade class plus the curated stable root, and use
moira.facade when you want direct imports for the admitted low-level API.
Topography-conditioned lunar contact chronology is a deliberate exception:
it remains available only from moira.lunar_occultation_contacts and
moira.lunar_limb while its validation boundary matures. It is not a facade,
package-root, or REST surface.
The complete admitted facade surface adds every remaining subsystem not exposed by the predictive tier:
- Heliacal visibility (5-criterion model)
- Parans and paran field analysis
- Church of Light natal Astrodynes
- AstroCartoGraphy, local space, geodetic charts
- Galactic coordinates
- Uranian / Hamburg School bodies
- Occultations and close approaches
- Harmograms (spectral harmonic analysis)
- Solar System Barycenter chart
- Planetocentric positions
- Received-light (light-cone) positions
- Variable and multiple star systems
- Constellations oracle (48 IAU constellations)
- Sothic cycle, Egyptian calendar
- Longevity (hyleg/alcocoden)
moira.vedic — Vedic astrology surface
from moira.vedic import * # includes everything from essentials, plus the full Vedic stack
A parallel surface for Vedic work. Inherits all of moira.essentials and adds:
| Added domain | Key symbols |
|---|---|
| Sidereal & Nakshatras | UserDefinedAyanamsa, NakshatraPosition, nakshatra_of, all_nakshatras_at |
| Panchanga | panchanga_at, sankranti_at, PanchangaResult, TithiPaksha, PanchangaPolicy |
| Pancha Pakshi | available_pancha_pakshi_profiles, pancha_pakshi_uromarisi_constitution_status, pancha_pakshi_profile_info, pancha_pakshi_identity_from_initial_vowel, pancha_pakshi_schedule, pancha_pakshi_first_eat_bird_mapping, pancha_pakshi_astronomical_paksha_at, pancha_pakshi_nakshatra_bird_mapping, pancha_pakshi_natal_moon_identity_at, pancha_pakshi_padu_bird_mapping, pancha_pakshi_sookshma_temporal_selection, pancha_pakshi_schedule_sookshma_temporal_selection, pancha_pakshi_civil_time_sookshma_selection_at, pancha_pakshi_local_solar_context_at, pancha_pakshi_fixed_clock_materialization_at, pancha_pakshi_fixed_clock_current_cell_at, pancha_pakshi_solar_proportional_materialization_at, pancha_pakshi_solar_proportional_current_cell_at, pancha_pakshi_directed_relationship |
| Vedic dignities | vedic_dignity, planetary_relationships, VedicDignityResult, DignityConditionProfile, ChartDignityProfile |
| Varga (divisional) | navamsa, saptamsa, dashamansa, dwadashamsa, trimshamsa + 11 more vargas, VargaPoint |
| Vimshottari Dasha | vimshottari, current_dasha, dasha_balance, dasha_active_line, DashaPeriod, VimshottariComputationPolicy |
| Alternate dashas | ashtottari, yogini_dasha, AlternateDashaPeriod, AshtottariPolicy, YoginiPolicy |
| Jaimini karakas | jaimini_karakas, atmakaraka, JaiminiKarakaResult, JaiminiPolicy |
| Ashtakavarga | bhinnashtakavarga, ashtakavarga, transit_strength, AshtakavargaResult, AshtakavargaPolicy |
| Shadbala | shadbala, sthana_bala, dig_bala, kala_bala, ShadbalaResult, ShadbalaPolicy |
moira.vedic does not include the Western classical surface (Arabic lots, Firdaria, Zodiacal Releasing, Huber). For that, use moira.classical. See Section 21 for the full export reference.
moira.sky — Strict astronomy API
moira.sky is a sovereign low-level astronomy surface that exposes Moira's computational substrate without astrological coupling. It is organized into ten submodules:
| Submodule | Purpose |
|---|---|
moira.sky.time | UT/TT/TDB conversions, ERA, GMST, GAST, LAST, ΔT decomposition |
moira.sky.position | Five-stage astrometric correction pipeline (light-time → aberration → deflection → frame bias → topocentric) |
moira.sky.frames | ICRF/ecliptic/equatorial/horizontal transforms, precession and nutation matrices |
moira.sky.visibility | Heliacal events, Yallop lunar crescent, arcus visionis, atmospheric extinction |
moira.sky.bodies | Geocentric, heliocentric, SSB, planetocentric, and topocentric body positions; nodes and apsides |
moira.sky.observation | Phase angle, illuminated fraction, apparent magnitude, elongation, Moon phases, apsides, conjunctions |
moira.sky.galactic | Galactic coordinate transforms (Liu, Zhu & Zhang 2011), reference point catalog |
moira.sky.events | Rise/set/transit, twilight times, stations and retrograde periods |
moira.sky.eclipse | Eclipse prediction, contact times, geographic paths, Saros/Metonic identification |
moira.sky.occultation | Lunar occultations of planets and stars, graze geometry, close approaches |
See Section 20 for the full submodule reference.
3. Core Types
Body — celestial body constants
from moira.facade import Body
Body.SUN Body.MOON Body.MERCURY Body.VENUS
Body.MARS Body.JUPITER Body.SATURN Body.URANUS
Body.NEPTUNE Body.PLUTO
Body.TRUE_NODE Body.MEAN_NODE Body.LILITH
Body.EARTH # for heliocentric computations
HouseSystem — house system constants
from moira.facade import HouseSystem
HouseSystem.PLACIDUS HouseSystem.KOCH HouseSystem.CAMPANUS
HouseSystem.REGIOMONTANUS HouseSystem.EQUAL HouseSystem.WHOLE_SIGN
HouseSystem.PORPHYRY HouseSystem.MORINUS HouseSystem.ALCABITIUS
HouseSystem.TOPOCENTRIC HouseSystem.MERIDIAN HouseSystem.VEHLOW
HouseSystem.SUNSHINE HouseSystem.AZIMUTHAL HouseSystem.CARTER
HouseSystem.KRUSINSKI HouseSystem.APC
Ayanamsa — sidereal reference frame
from moira.facade import Ayanamsa
Ayanamsa.LAHIRI # IAU standard; default for Vedic work
Ayanamsa.FAGAN_BRADLEY
Ayanamsa.RAMAN
Ayanamsa.TRUE_CHITRAPAKSHA
Ayanamsa.KRISHNAMURTI
Ayanamsa.SASSANIAN
# + dozens more — see list_ayanamsa_systems()
AspectDefinition and ASPECT_TIERS
AspectDefinition specifies a single aspect angle with its name, symbol, orb, and tier. Used to add custom aspects or override defaults.
from moira.facade import AspectDefinition, ASPECT_TIERS
custom = AspectDefinition(name="Quintile", symbol="Q", angle=72.0, orb=2.0, tier=3)
ASPECT_TIERS: dict[int, str] mapping tier number → descriptive label (e.g. {1: "Major", 2: "Minor", 3: "Harmonic"}). Used to filter aspects by significance level via AspectPolicy.
Chart — planetary snapshot vessel
Produced by Moira.chart(). Carries the full positional state of the sky at
one Julian Day.
| Field | Type | Description |
|---|---|---|
jd_ut | float | Legacy field name: UTC-coded Julian Day of the civil snapshot; internal reductions resolve UT1 explicitly, preserving the historical proxy before the monotonic final-day handoff into the admitted atomic UTC era |
planets | dict[str, PlanetData] | Geocentric ecliptic positions |
nodes | dict[str, NodeData] | Lunar nodes and Lilith |
obliquity | float | True obliquity of the ecliptic (°) |
delta_t | float | ΔT = TT − UT1 in seconds at the resolved astronomical instant |
Properties:
| Property | Returns | Description |
|---|---|---|
datetime_utc | datetime | UTC datetime for this snapshot |
calendar_utc | CalendarDateTime | BCE-safe calendar breakdown |
Methods:
| Method | Returns | Description |
|---|---|---|
longitudes(include_nodes=True) | dict[str, float] | Flat dict of body → ecliptic longitude |
speeds() | dict[str, float] | Body → daily longitude speed (°/day) |
PlanetData — single planet position
| Field | Type | Description |
|---|---|---|
longitude | float | Ecliptic longitude, tropical (°) |
latitude | float | Ecliptic latitude (°) |
speed | float | Daily motion in longitude (negative = retrograde) |
distance | float | Distance from Earth (km) |
NodeData — lunar node position
| Field | Type | Description |
|---|---|---|
longitude | float | Ecliptic longitude (°) |
speed | float | Daily motion (°/day) |
SkyPosition — topocentric equatorial/horizontal
| Field | Type | Description |
|---|---|---|
right_ascension | float | Apparent RA (°) |
declination | float | Apparent Dec (°) |
altitude | float | Altitude above horizon (°) |
azimuth | float | Azimuth, North = 0° (°) |
distance | float | Distance (km) |
HouseCusps — computed house frame
| Field | Type | Description |
|---|---|---|
cusps | tuple[float, ...] | 12 house cusp longitudes (°), index 0 = cusp 1 |
asc | float | Ascendant (°) |
mc | float | Midheaven (°) |
armc | float | ARMC — Sidereal time × 15 (°) |
east_point | float | East Point / Equatorial Ascendant longitude (°) |
vertex | float | Vertex longitude (°) |
system | str | Requested house system code |
effective_system | str | Effective system code after policy resolution |
fallback | bool | Whether fallback policy altered the requested system |
fallback_reason | str | None | Human-readable fallback reason, if any |
classification | HouseSystemClassification | Classification of the effective house system |
policy | HousePolicy | Governing house policy used to compute the result |
4. Moira Facade
Moira(kernel_path=None) is the primary entry point. All methods convert
datetime inputs to JD internally. datetime arguments must be timezone-aware;
naïve datetimes are rejected.
Construction
m = Moira()
m = Moira(kernel_path="/path/to/de441.bsp")
Construction is tolerant: if no planetary kernel is currently available, the
instance still initializes and defers failure until a kernel-dependent method
is called. Those calls raise MissingEphemerisKernelError with a diagnostic
message.
Kernel readiness & management
| Member | Returns | Description |
|---|---|---|
is_kernel_available() | bool | Whether a planetary kernel is ready right now |
get_kernel_status() | str | Human-readable kernel readiness message |
kernel_status | str | Property alias of get_kernel_status() |
available_kernels | list[str] | Installed planetary and supplemental kernel filenames |
configure_kernel_path(path) | None | Configure and validate an explicit planetary kernel path |
download_missing_kernels(interactive=False) | None | Download missing kernels into the standard user directory |
Core chart methods
| Method | Returns | Description |
|---|---|---|
chart(dt, bodies=None, include_nodes=True, observer_lat=None, observer_lon=None, observer_elev_m=0.0) | Chart | Complete planetary snapshot; supply observer coords for topocentric Moon |
houses(dt, latitude, longitude, system=HouseSystem.PLACIDUS, policy=None) | HouseCusps | House cusps, angles, ARMC under explicit house policy when supplied |
sky_position(dt, body, latitude, longitude, elevation_m=0.0) | SkyPosition | Apparent topocentric RA/Dec + altitude/azimuth |
sidereal_chart(dt, ayanamsa_system=Ayanamsa.LAHIRI, bodies=None) | dict[str, float] | Body → sidereal longitude |
heliocentric(dt, bodies=None) | dict[str, HeliocentricData] | Heliocentric ecliptic positions |
phase(body, dt) | dict | Phase angle, illumination, angular diameter, apparent magnitude |
twilight(dt, latitude, longitude) | TwilightTimes | Civil/nautical/astronomical twilight times |
Aspects & patterns
| Method | Returns | Description |
|---|---|---|
aspects(chart, orbs=None, include_minor=True, *, tier=None, orb_factor=1.0, policy=None) | list[AspectData] | All natal aspects with the complete owning-module policy surface forwarded |
hellenistic_superiority_truth(longitude1, longitude2, aspect_angle=None, *, body1="body1", body2="body2") | HellenisticSuperiorityTruth | Raw direction applicability plus tenth-sign overcoming for one ordered pair |
patterns(chart, orb_factor=1.0, dominant_only=False) | list[AspectPattern] | Named aspect patterns built from the chart's positions and aspects, with optional maximal-structure filtering |
midpoints(chart, planet_set="classic") | list[Midpoint] | Planetary midpoints for the requested body set |
midpoints_to_point(chart, longitude, orb=1.5) | list[tuple[Midpoint, float]] | Midpoints falling at a given longitude, paired with absolute orb |
harmonic(chart, number) | list[HarmonicPosition] | Integer cyclic harmonic or zero-Aries-anchored positive-real continuous multiplier |
harmonic_transit_forecast(natal_longitudes, transit_samples, policy) | HarmonicTransitForecast | Sampled VA-informed complete mixed-origin triples; no interpolation or exact-contact claim |
antiscia(chart, orb=1.0) | list[AntisciaAspect] | Antiscia and contra-antiscia aspects |
Dignities & essential condition
| Method | Returns | Description |
|---|---|---|
dignities(chart, houses, *, policy=None) | list[PlanetaryDignity] | Essential and accidental dignities with lossless policy forwarding |
lots(chart, houses, *, policy=None, syzygy=None, prenatal_new_moon=None, prenatal_full_moon=None, lord_of_hour=None) | list[ArabicPart] | Arabic Parts / Hermetic Lots with nodes and optional external references preserved |
evaluate_lots(chart, houses, *, policy=None, syzygy=None, prenatal_new_moon=None, prenatal_full_moon=None, lord_of_hour=None) | LotsEvaluation | Lossless lot catalogue evaluation including typed unresolved entries |
hellenistic_chart_profile(chart, houses, natal_dt, current_dt, *, civil_timezone=None, policy=None, ...) | HellenisticChartProfile | Score-free composition of admitted Hellenistic atomic receipts from an explicit no-fallback Whole Sign chart |
solar_proximity_truth(...), planetary_solar_phase_truth(...), besieging_truth(...) | typed raw receipts | Raw dignity geometry before compatibility labels or score assembly |
mutual_receptions(chart, by_exaltation=False) | list[tuple] | (planet_a, planet_b, type) mutual reception triples |
astrodynes(body_inputs, cusp_signs, intercepted_signs_by_house=None, policy=None) | AstrodyneChartResult | Kernel-free Church of Light natal Astrodynes from explicit chart geometry |
Classical techniques
| Method | Returns | Description |
|---|---|---|
profection(natal_asc, natal_dt, current_dt, natal_positions=None, *, civil_timezone=None, leap_day_policy=None, ambiguous_time_policy=None, interval_policy=..., activation_orb=5.0) | ProfectionResult | Annual profection plus the exact dated monthly chronology |
profection_chronology(natal_asc, natal_dt, current_dt, *, civil_timezone=None, leap_day_policy=None, ambiguous_time_policy=None, interval_policy=...) | ProfectionChronology | Raw dated monthly profection receipt |
nakshatras(chart, ayanamsa_system=Ayanamsa.LAHIRI) | dict[str, NakshatraPosition] | Nakshatra for each planet |
planetary_hours(dt, latitude, longitude) | PlanetaryHoursDay | Day and night planetary hour rulers |
Timing techniques
| Method | Returns | Description |
|---|---|---|
transits(body, target_lon, jd_start, jd_end) | list[TransitEvent] | All transits of a body to a natal point |
ingresses(body, jd_start, jd_end) | list[IngressEvent] | All sign ingresses in a date range |
next_ingress(body, jd_start, max_days=None) | IngressEvent | None | Next sign ingress of any kind |
next_ingress_into(body, sign, jd_start, max_days=None) | IngressEvent | None | Next entry into a specific sign |
solar_return(natal_sun_lon, year) | float | JD UT of the Solar Return in a calendar year |
lunar_return(natal_moon_lon, jd_start) | float | JD UT of the next Lunar Return |
planet_return(body, natal_lon, jd_start, direction="direct") | float | JD UT of the next planetary return |
syzygy(jd) | tuple[float, str] | (jd_ut, kind) of prenatal syzygy |
stations(body, jd_start, jd_end) | list[StationEvent] | Retrograde and direct stations |
retrograde_periods(body, jd_start, jd_end) | list[tuple[float, float]] | List of (jd_start, jd_end) retrograde intervals |
moon_void_of_course(dt, ...) / is_moon_void_of_course(dt, ...) | — | See Void of Course Moon subsection below |
electional_windows(dt_start, dt_end, ...) | — | See Electional search subsection below |
ramesey_moon_condition_at(jd_ut, latitude, longitude, *, house_system, ...) | RameseyMoonConditionEvaluation | One bounded Ramesey v1 Moon-condition evaluation; no search, score, or recommendation |
Progressions & directions
| Method | Returns | Description |
|---|---|---|
progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Secondary progression (1 day = 1 year) |
solar_arc_directions(natal_dt, target_dt, bodies=None) | ProgressedChart | Solar Arc directed chart |
solar_arc_directions_ra(natal_dt, target_dt, bodies=None) | ProgressedChart | Solar Arc in right ascension |
naibod_in_longitude(natal_dt, target_dt, bodies=None) | ProgressedChart | Naibod directions in ecliptic longitude |
naibod_in_right_ascension(natal_dt, target_dt, bodies=None) | ProgressedChart | Naibod directions in right ascension |
tertiary_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Tertiary progression (1 day = 1 lunar month) |
tertiary_ii_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Tertiary II / Klaus Wessel |
minor_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Minor progression (1 lunar month = 1 year) |
ascendant_arc_directions(natal_dt, target_dt, latitude, longitude, bodies=None) | ProgressedChart | Ascendant Arc directed chart |
daily_house_frame(natal_dt, target_dt, latitude, longitude, system=...) | HouseCusps | Daily Houses progressed frame |
converse_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Secondary Progressed |
converse_solar_arc(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Solar Arc |
converse_solar_arc_ra(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Solar Arc in RA |
converse_naibod_in_longitude(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Naibod in longitude |
converse_naibod_in_right_ascension(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Naibod in RA |
converse_tertiary_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Tertiary |
converse_tertiary_ii_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Tertiary II |
converse_minor_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse Minor |
duodenary_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Duodenary progression |
converse_duodenary_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse duodenary progression |
quotidian_solar_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Solar quotidian progression |
converse_quotidian_solar_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse solar quotidian progression |
quotidian_lunar_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Lunar quotidian progression |
converse_quotidian_lunar_progression(natal_dt, target_dt, bodies=None) | ProgressedChart | Converse lunar quotidian progression |
planetary_arc_directions(natal_dt, target_dt, arc_body, bodies=None) | ProgressedChart | Planetary-arc directed chart |
converse_planetary_arc_directions(natal_dt, target_dt, arc_body, bodies=None) | ProgressedChart | Converse planetary-arc directed chart |
speculum(chart, houses, geo_lat, *, obliquity=None, bodies=None) | list[SpeculumEntry] | Speculum with established positional compatibility and additive explicit inputs |
primary_directions(chart, houses, geo_lat, max_arc=90.0, include_converse=True, significators=None, promissors=None, *, solar_speed=None, obliquity=None, policy=None) | list[PrimaryArc] | Primary-direction arcs under an explicit optional policy; established positional inputs are unchanged |
primary_directions_policy_preset(preset, **kwargs) | PrimaryDirectionsPolicy | Build one canonical typed policy preset |
primary_direction_relations(arc, *, policy=None) | PrimaryDirectionRelationProfile | Evaluate one arc's admitted/scored relation truth |
primary_direction_condition(arcs, *, policy=None) | PrimaryDirectionsSignificatorProfile | Evaluate one significator's directed condition |
primary_directions_profile(arcs, *, policy=None) | PrimaryDirectionsAggregateProfile | Evaluate a chart-wide primary-directions aggregate |
primary_directions_network(arcs, *, policy=None) | PrimaryDirectionsNetworkProfile | Evaluate the directed promissor-to-significator graph |
Hellenistic & Vedic time lords
| Method | Returns | Description |
|---|---|---|
firdaria(natal_dt, natal_chart, natal_houses) | list[FirdarPeriod] | Persian Firdaria sequence; explicit houses and Sun are required for sect |
decennials(natal_dt, natal_chart, natal_houses, *, levels=2, policy=None) | list[DecennialPeriod] | Admitted L1/L2 Decennials sequence with explicit sect and time-basis truth |
current_decennials(natal_dt, current_dt, natal_chart, natal_houses, *, levels=2, policy=None) | tuple[DecennialPeriod, DecennialPeriod] | Active Decennials major/sub-period on the elapsed lived-day coordinate |
zodiacal_releasing(lot_longitude, natal_dt, levels=4, *, lot_name="Spirit", fortune_longitude=None, use_loosing_of_bond=True, policy=None) | list[ReleasingPeriod] | Zodiacal Releasing with all doctrine inputs forwarded |
vimshottari_dasha(natal_chart, natal_dt, levels=2, ayanamsa_system=Ayanamsa.LAHIRI) | list[DashaPeriod] | Vimshottari Dasha sequence from Moon nakshatra |
Synastry & relationship charts
| Method | Returns | Description |
|---|---|---|
synastry_aspects(chart_a, chart_b, tier=2, orbs=None, orb_factor=1.0, include_nodes=True) | list[AspectData] | Inter-aspects between two natal charts |
house_overlay(chart_source, target_houses, include_nodes=True, source_label="A", target_label="B") | SynastryHouseOverlay | Place chart_source planets in target_houses |
mutual_house_overlays(chart_a, houses_a, chart_b, houses_b, include_nodes=True) | MutualHouseOverlay | Both overlay directions in one call |
composite_chart(chart_a, chart_b, houses_a=None, houses_b=None) | CompositeChart | Midpoint composite |
aspects_from_longitudes(longitudes, *, tier=1, orb_factor=1.0, include_nodes=True) | LongitudeAspectAnalysis | Canonical position-only aspect analysis for a derived chart; no speeds or moment inferred |
composite_chart_reference_place(chart_a, chart_b, houses_a, houses_b, reference_latitude, house_system=..., policy=None) | CompositeChart | Reference-place composite house method with explicit synastry policy when supplied |
davison_chart(dt_a, lat_a, lon_a, dt_b, lat_b, lon_b, house_system=..., policy=None) | DavisonChart | Davison Relationship Chart (spherical midpoint time + location) |
davison_chart_uncorrected(...) | DavisonChart | Davison with arithmetic midpoints |
davison_chart_reference_place(dt_a, dt_b, ref_lat, ref_lon, house_system=...) | DavisonChart | Davison with midpoint time and explicit place |
davison_chart_spherical_midpoint(...) | DavisonChart | Davison with midpoint time and spherical geographic midpoint |
davison_chart_corrected(...) | DavisonChart | Davison with midpoint location and corrected time |
The REST forms POST /v1/composite/chart and POST /v1/davison/chart include
a required aspects analysis of the returned chart's own longitudes. The
request's tier, orb_factor, and include_nodes fields govern that nested
analysis, whose computation truth preserves the absence of speed-derived
motion semantics.
Geography
| Method | Returns | Description |
|---|---|---|
astrocartography(chart, observer_lat=0.0, observer_lon=0.0, bodies=None, lat_step=2.0) | list[ACGLine] | ACG lines (MC/IC/ASC/DSC) for all planets |
local_space(chart, latitude, longitude, bodies=None) | list[LocalSpacePosition] | Horizon azimuth and altitude for each planet |
gauquelin_sectors(chart, latitude, longitude, bodies=None) | list[GauquelinPosition] | Gauquelin sector placements for chart bodies at a location |
Fixed stars, mansions & parans
| Method | Returns | Description |
|---|---|---|
fixed_star(name, dt) | FixedStar | Unified star position enriched with Gaia DR3 data |
heliacal_rising(star_name, dt, latitude, longitude) | float | None | JD UT of the next heliacal rising |
heliacal_setting(star_name, dt, latitude, longitude) | float | None | JD UT of the next heliacal setting |
heliacal_rising_event(star_name, dt, latitude, longitude) | HeliacalEvent | Full heliacal-rising event vessel with classification metadata |
heliacal_setting_event(star_name, dt, latitude, longitude) | HeliacalEvent | Full heliacal-setting event vessel with classification metadata |
lunar_mansions(chart) | dict[str, MansionPosition] | Arabic lunar mansion placement for chart bodies |
parans(natal_dt, latitude, longitude, bodies=None, orb_minutes=4.0) | list[Paran] | Paran crossings for the chart date and location |
Alternative frames & specialty coordinates
| Method | Returns | Description |
|---|---|---|
planetary_nodes(dt) | dict[str, OrbitalNode] | Heliocentric orbital nodes and apsides for the planets |
planetocentric(observer, dt, bodies=None) | dict[str, PlanetocentricData] | Positions as seen from the center of the observer body |
ssb_chart(dt, bodies=None) | dict[str, SSBPosition] | Solar System barycenter positions in the standard of-date ecliptic frame |
received_light(dt, bodies=None) | dict[str, ReceivedLightPosition] | Apparent received-light positions with explicit light-cone geometry |
galactic_chart(chart, bodies=None) | list[GalacticPosition] | Galactic longitude/latitude for chart bodies |
galactic_angles(chart) | dict[str, tuple[float, float]] | Ecliptic long/lat of major galactic reference points |
uranian(dt) | dict[str, UranianPosition] | Positions of the current nine Uranian/Hamburg School and Transpluto hypothetical bodies |
geodetic(chart, zodiac="tropical", ayanamsa_system=None) | GeodeticChart | Geodetic chart frame derived from planetary longitudes |
geodetic_planet_equivalents(chart, bodies=None, zodiac="tropical", ayanamsa_system=None) | dict[str, float] | Geodetic longitude equivalents for selected bodies |
synodic_phase(body1, body2, dt) | dict[str, float | str] | Synodic separation, cycle fraction, and phase label for two bodies |
galactic_houses(dt, latitude, longitude) | GalacticHouseCusps | Galactic Porphyry house cusps for a time and observer location; cusps_gal gives native galactic membership, cusps_ecl provides ecliptic interoperability |
Phenomena & occultations
| Method | Returns | Description |
|---|---|---|
phenomena(body, jd_start, jd_end) | list[PhenomenonEvent] | Greatest elongations, perihelion, and aphelion events in a range |
moon_phases(jd_start, jd_end) | list[PhenomenonEvent] | All eight standard Moon phases in a date range |
next_conjunction(body1, body2, jd_start, max_days=1200.0) | PhenomenonEvent | None | Next conjunction of two bodies |
conjunctions(body1, body2, jd_start, jd_end) | list[PhenomenonEvent] | All conjunctions of two bodies in a date range |
resonance(body1, body2) | OrbitalResonance | Best-fit orbital resonance relation between two bodies |
occultations(jd_start, jd_end, targets=None) | list[LunarOccultation] | Lunar occultations of the default planet set or supplied targets |
close_approaches(body1, body2, jd_start, jd_end, max_sep_deg=1.0) | list[CloseApproach] | Close approaches between two bodies in a date range |
Traditional, historical & diagnostic methods
| Method | Returns | Description |
|---|---|---|
longevity(chart, houses) | HylegResult | Traditional hyleg and alcocoden longevity analysis |
sothic_cycle(latitude, longitude, year_start, year_end, arcus_visionis=10.0) | list[SothicEntry] | Year-by-year heliacal risings of Sirius across a date span |
sothic_epoch_finder(latitude, longitude, year_start, year_end, tolerance_days=1.0) | list[SothicEpoch] | Candidate Sothic epochs across a year range |
egyptian_date(dt, epoch_jd=None) | EgyptianDate | Egyptian civil calendar date for a datetime |
Variable & multiple stars
| Method | Returns | Description |
|---|---|---|
variable_star_phase(name, dt) | float | Current variable-star phase at a datetime |
variable_star_magnitude(name, dt) | float | Estimated V magnitude at a datetime |
variable_star_next_minimum(name, dt) | float | None | JD of the next primary minimum |
variable_star_next_maximum(name, dt) | float | None | JD of the next maximum |
variable_star_minima(name, jd_start, jd_end) | list[float] | All minima JDs in a range |
variable_star_maxima(name, jd_start, jd_end) | list[float] | All maxima JDs in a range |
variable_star_quality(name, dt) | dict[str, float | bool] | Phase, magnitude, benefic/malefic quality metrics, and eclipse state |
multiple_star_separation(name, dt, aperture_mm=100.0) | dict | Separation, PA, resolvability, and brightness summary |
multiple_star_components(name, dt) | dict | Full component snapshot for a multiple star system |
Void of Course Moon
| Method | Returns | Description |
|---|---|---|
moon_void_of_course(dt, modern=False) | VoidOfCourseWindow | Void-of-course window for the Moon's current sign |
is_moon_void_of_course(dt, modern=False) | bool | Whether the Moon is void of course at the given datetime |
Electional search
| Method | Returns | Description |
|---|---|---|
electional_windows(dt_start, dt_end, latitude, longitude, predicate, policy=None) | list[ElectionalWindow] | Search a date range for windows whose chart context satisfies the predicate |
Low-level JD-based electional search is also public:
from moira.facade import ElectionalPolicy, ElectionalWindow
from moira.facade import find_electional_windows, find_electional_moments
| Function | Returns | Description |
|---|---|---|
find_electional_windows(jd_start, jd_end, latitude, longitude, predicate, policy=None, reader=None) | list[ElectionalWindow] | Window search directly on Julian dates |
find_electional_moments(jd_start, jd_end, latitude, longitude, predicate, policy=None, reader=None) | list[float] | Exact candidate JDs for matching electional moments |
Western electional moment evaluation
Source-owned Western profiles are separate from generic electional search:
from moira import (
RAMESEY_MOON_CONDITION_V1,
RameseyMoonConditionEvaluation,
ramesey_moon_condition_at,
)
evaluation = engine.ramesey_moon_condition_at(
jd_ut,
latitude,
longitude,
house_system="R",
unavoidable_time_urgency=None,
)
| Surface | Returns | Description |
|---|---|---|
Moira.ramesey_moon_condition_at(jd_ut, latitude, longitude, *, house_system, unavoidable_time_urgency=None, house_policy=None, policy=None) | RameseyMoonConditionEvaluation | Reader-backed single-moment facade entry point; defaults to the immutable Ramesey v1 policy |
ramesey_moon_condition_at(jd_ut, latitude, longitude, *, house_system, unavoidable_time_urgency=None, reader=None, house_policy=None, policy=RAMESEY_MOON_CONDITION_V1) | RameseyMoonConditionEvaluation | Low-level JD evaluator with explicit reader support |
evaluate_ramesey_moon_condition(chart, *, ...) | RameseyMoonConditionEvaluation | Evaluate the named profile from an explicitly compatible chart product |
The same public ladder now includes:
| Surface | Returns | Description |
|---|---|---|
Moira.sahl_moon_condition_at(...) | SahlMoonConditionEvaluation | Single-moment Sahl section 22 Moon-condition evaluation |
Moira.dorotheus_moon_condition_at(...) | DorotheusMoonConditionEvaluation | Single-moment Dorotheus V.6 Moon-condition and remedy witness |
Moira.dorotheus_rooted_context_at(...) | DorotheusRootedContextEvaluation | V.6/V.31 root, outcome, matter-significator, and natal-context evidence |
Moira.dorotheus_construction_at(...) | DorotheusConstructionEvaluation | Complete V.2-V.7 construction matter profile without scoring or recommendation |
Moira.dorotheus_matter_profile_at(..., profile_id=...) | DorotheusMatterProfileEvaluation | Named Dorotheus Book V matter profile, including V.20 partnership, V.21 debt/payment, V.22 travel, V.24–V.26 ship work, and V.43 wills; V.26.39–43 land/sea profiles require an explicit sign-nature variant |
Moira.western_electional_profile_windows(...) | WesternElectionalProfileScan | Bounded discrete status-window scan for one admitted Moon profile |
dorotheus_construction_v1 exposes the IERS-backed signed lunar equation in
its first construction clause while retaining the source-unspecified
ecliptic-crossing clause as not_evaluable. Its nested rooted context evaluates
V.31 bad-place membership as whole-sign places 3, 6, 8, and 12. The corresponding
REST transports are documented in wiki/02_services/REST_API_REFERENCE.md.
The matter-profile facade accepts an explicit DorotheusMatterProfileId and
uses one stable result vessel for every admitted topic. The profile id, matter,
source-ordered clauses, whole-sign angular witnesses, policy, and completeness
flags remain explicit; V.9 lunar flow is not inferred from the forward
connection alone. V.20 partnership and V.21 debt/payment retain their
Mercurial V.31 context. V.22 travel, V.24 acquisition, V.25 construction,
V.26 launch, and V.43 will writing deliberately have none; V.26 alone may
receive a complete radical chart for the chapter-owned Saturn overlay. Each
source-open term remains not_evaluable rather than receiving an invented
sign list, degree interval, or historical score.
The package root and moira.facade export the admitted profile constants,
evaluator functions, policy/evaluation vessels, and their named witnesses and
enums. Results retain their source-ordered rules and explicit unresolved
semantics. They deliberately report
complete_electional_judgement=False, with no score, advice, recommendation,
generic search integration, or remedy-fulfillment assessment.
Julian Day utilities
| Method | Returns | Description |
|---|---|---|
jd(year, month, day, hour=0.0) | float | JD from a proleptic Gregorian calendar date |
from_jd(jd) | datetime | UTC datetime from a JD |
calendar_from_jd(jd) | CalendarDateTime | BCE-safe calendar breakdown from a JD |
Eclipse
| Method | Returns | Description |
|---|---|---|
eclipse(dt) | EclipseData | Full eclipse geometry and classification for a datetime |
solar_eclipse_footprint(jd_start, *, kind="any", backward=False, sample_count=181) | SolarEclipseVisibilityFootprint | Complete zero-elevation WGS 84 mean-limb penumbral visibility boundary |
solar_global_circumstances(jd_start, *, kind="any", backward=False) | SolarEclipseGlobalCircumstances | Scale-explicit global contacts, conjunctions, GE/GD, body states, and provenance |
solar_eclipse_cartography(jd_start, *, kind="any", backward=False, magnitude_levels=..., obscuration_levels=..., mesh_depth=1, time_samples=17, angular_tolerance_deg=8.0, field_tolerance=0.01) | SolarEclipseCartography | NumPy-free adaptive spherical maximum-visible magnitude and obscuration contours |
lunar_global_circumstances(jd_start, *, kind="any", backward=False, mode="native") | LunarEclipseGlobalCircumstances | Mode-pure geocentric contacts, parameters, body states, and durations |
lunar_eclipse_visibility_map(jd_start, *, kind="any", backward=False, mode="native", sample_count=181) | LunarEclipseVisibilityMap | Global contact-horizon limits for lunar-eclipse map rendering |
5. Ephemeris & Positions
Planetary positions — low-level functions
from moira.facade import planet_at, all_planets_at, sky_position_at
from moira.spk_reader import get_reader
reader = get_reader()
jd = 2451545.0 # J2000.0
pos = planet_at("Jupiter", jd, reader=reader)
# PlanetData(longitude, latitude, speed, distance)
sky = sky_position_at("Mars", jd, observer_lat=51.5, observer_lon=-0.1, reader=reader)
# SkyPosition(right_ascension, declination, altitude, azimuth, distance)
chart_dict = all_planets_at(jd, reader=reader)
# dict[str, PlanetData] for all ten classical planets
The unified planet_at, all_planets_at, and sky_position_at body namespace
also admits cataloged asteroids and comets. A globally unique name resolves
directly. A name present in both families must be qualified, for example
"asteroid:Halley" or "comet:Halley"; an unqualified collision raises
AmbiguousSmallBodyNameError instead of selecting a family by lookup order.
Canonical comet designations such as "1P/Halley" remain globally
unambiguous. Dedicated asteroid_at and comet_at calls retain their
family-local name rules.
| Function | Returns | Description |
|---|---|---|
planet_at(body, jd_ut, reader=None, observer_lat=None, observer_lon=None, observer_elev_m=0.0) | PlanetData | Single planet geocentric ecliptic position |
all_planets_at(jd_ut, bodies=None, reader=None, ...) | dict[str, PlanetData] | All (or specified) planets at one JD |
sky_position_at(body, jd_ut, observer_lat, observer_lon, observer_elev_m=0.0, reader=None) | SkyPosition | Apparent topocentric equatorial + horizontal coords |
planet_reduction_breakdown_at(body, jd_ut, reader=None, ...) | PlanetReductionBreakdown | Ordered visible longitude-reduction stages as PlanetReductionStage records |
sun_longitude(jd_ut, reader=None) | float | Sun ecliptic longitude only (faster than planet_at) |
Lunar nodes
| Function | Returns | Description |
|---|---|---|
true_node(jd_ut, reader=None) | NodeData | True (osculating) lunar node |
mean_node(jd_ut, *, nutation=True) | NodeData | IERS 2003 mean lunar node; true equinox of date by default, raw mean equinox with nutation=False |
mean_lilith(jd_ut, *, nutation=True) | NodeData | Mean Black Moon Lilith; true equinox of date by default, raw mean equinox with nutation=False |
Nodes & apsides bundle
from moira.facade import NodesAndApsides, nodes_and_apsides_at, next_moon_node_crossing
| Function | Returns | Description |
|---|---|---|
nodes_and_apsides_at(body, jd_ut) | NodesAndApsides | Combined node/apsides vessel for the Moon or supported orbital bodies |
next_moon_node_crossing(jd_start, reader=None, ascending=True) | float | JD UT of the next ascending or descending lunar node crossing |
Heliocentric positions
from moira.facade import heliocentric_planet_at, all_heliocentric_at, HeliocentricData
| Function | Returns | Description |
|---|---|---|
heliocentric_planet_at(body, jd_ut, reader=None) | HeliocentricData | Heliocentric ecliptic longitude, latitude, distance |
all_heliocentric_at(jd_ut, bodies=None, reader=None) | dict[str, HeliocentricData] | All planets heliocentrically |
Asteroids
from moira.facade import asteroid_at, all_asteroids_at, list_asteroids
from moira.facade import load_asteroid_kernel # for non-DE441 bodies
| Function | Returns | Description |
|---|---|---|
asteroid_at(name_or_id, jd_ut, reader=None) | AsteroidData | Single asteroid geocentric ecliptic position |
all_asteroids_at(jd_ut, reader=None) | dict[str, AsteroidData] | All loaded asteroids |
list_asteroids() | list[str] | Names of currently loaded asteroids |
available_in_kernel(kernel_path) | list[str] | Asteroid names available in a kernel |
load_asteroid_kernel(path) | — | Load a supplementary SPK kernel |
load_secondary_kernel(path) | — | Load second SPK kernel |
load_tertiary_kernel(path) | — | Load third SPK kernel |
Planetary nodes (apsides)
| Function | Returns | Description |
|---|---|---|
planetary_node(body, jd_ut) | OrbitalNode | Ascending node and perihelion for a planet |
all_planetary_nodes(jd_ut) | dict[str, OrbitalNode] | All planetary nodes |
Uranian planets (Hamburg School)
from moira.facade import uranian_at, all_uranian_at, list_uranian, UranianBody, UranianPosition
| Function | Returns | Description |
|---|---|---|
uranian_at(body, jd_ut) | UranianPosition | Single Uranian body position |
all_uranian_at(jd_ut) | dict[str, UranianPosition] | All current nine Uranian/Hamburg School and Transpluto hypothetical bodies |
list_uranian() | list[str] | Uranian body names (Cupido through Poseidon, plus Transpluto) |
UranianBody constants: CUPIDO HADES ZEUS KRONOS APOLLON ADMETOS VULKANUS POSEIDON TRANSPLUTO
Galactic coordinates
from moira.facade import (
galactic_position_of, all_galactic_positions, galactic_reference_points,
equatorial_to_galactic, galactic_to_equatorial,
ecliptic_to_galactic, galactic_to_ecliptic,
GalacticPosition,
)
| Function | Returns | Description |
|---|---|---|
galactic_position_of(body, ecliptic_lon, ecliptic_lat, obliquity, jd_tt) | GalacticPosition | Galactic longitude and latitude (IAU 1958) for one body from true-of-date ecliptic coordinates |
all_galactic_positions(body_data, obliquity, jd_tt) | list[GalacticPosition] | Galactic positions for a dict of body -> (lon, lat) using the chart's TT epoch |
galactic_reference_points(obliquity, jd_tt) | dict[str, tuple[float, float]] | GC, anti-GC, NGP, SGP, and super-galactic center in true ecliptic-of-date coordinates |
equatorial_to_galactic(ra, dec) | tuple[float, float] | RA/Dec -> galactic (l, b) |
galactic_to_equatorial(l, b) | tuple[float, float] | Galactic -> RA/Dec |
ecliptic_to_galactic(lon, lat, obliquity, jd_tt) | tuple[float, float] | True ecliptic-of-date -> galactic, with TT epoch used for the J2000 frame bridge |
galactic_to_ecliptic(l, b, obliquity, jd_tt) | tuple[float, float] | Galactic -> true ecliptic-of-date, with TT epoch used for the of-date frame bridge |
Gauquelin sectors
from moira.facade import (
GauquelinHorizonStatus,
GauquelinPosition,
gauquelin_sector,
all_gauquelin_sectors,
)
| Function | Returns | Description |
|---|---|---|
gauquelin_sector(body_ra, body_dec, lat, lst, body="", horizon_altitude=0.0, sectors=36) | GauquelinPosition | Gauquelin sector for a single apparent RA/Dec position at geographic latitude and local sidereal time; non-rising geometry returns an explicit status with nullable sector-derived fields |
all_gauquelin_sectors(planet_ra_dec, lat, lst, horizon_altitude=0.0, sectors=36) | list[GauquelinPosition] | Gauquelin sectors for a dict of body -> (ra, dec) |
GauquelinPosition: body, sector, zone, diurnal_position, sectors, degree_in_sector, is_plus_zone, horizon_status.
sector, diurnal_position, and degree_in_sector are None when the body
does not have an ordinary rise/set pair at the selected horizon.
GauquelinHorizonStatus: NORMAL, CIRCUMPOLAR, NEVER_RISES,
HORIZON_COINCIDENT.
Coordinate utilities
from moira.facade import (
icrf_to_ecliptic, icrf_to_equatorial, ecliptic_to_equatorial,
equatorial_to_horizontal, horizontal_to_equatorial,
cotrans_sp,
atmospheric_refraction, atmospheric_refraction_extended,
equation_of_time,
angular_distance, normalize_degrees,
)
| Function | Signature | Description |
|---|---|---|
ecliptic_to_equatorial | (lon, lat, obliquity) -> (ra, dec) | Ecliptic -> equatorial (degrees) |
equatorial_to_horizontal | (ha, dec, lat) -> (az, alt) | Hour angle/Dec -> azimuth/altitude |
horizontal_to_equatorial | (azimuth_deg, altitude_deg, lst_deg, lat_deg) -> (ra, dec) | Horizontal coordinates -> equatorial coordinates |
cotrans_sp | (lon, lat, dist, lon_speed, lat_speed, dist_speed, obliquity) -> tuple[...] | Simultaneous spherical coordinate and speed transformation |
atmospheric_refraction | (altitude_deg, *, pressure_mbar=..., temperature_c=...) -> float | Standard apparent-altitude refraction correction (degrees) |
atmospheric_refraction_extended | (altitude_deg, *, pressure_mbar=..., temperature_c=..., relative_humidity=..., observer_height_m=..., wavelength_micron=...) -> tuple[float, float] | Extended refraction model with environmental parameters |
equation_of_time | (jd_tt) -> float | Equation of time in minutes at the TT epoch |
angular_distance | (lon1, lat1, lon2, lat2) -> float | Great-circle distance (degrees) |
normalize_degrees | (d) -> float | Map any angle to [0, 360) |
Phase & apparent magnitude
from moira.facade import angular_diameter
ang_diam_arcsec = angular_diameter("Moon", jd)
# For full phase metrics use Moira.phase():
result = m.phase("Venus", dt)
# keys: phase_angle, illumination, angular_diameter_arcsec, apparent_magnitude
Twilight
from moira.facade import twilight_times, TwilightTimes
t = twilight_times(jd, latitude=51.5, longitude=-0.1)
# TwilightTimes: civil_dawn, civil_dusk, nautical_dawn, nautical_dusk,
# astro_dawn, astro_dusk, sunrise, sunset (all JD UT)
Relative-motion, orbital, and event helpers
from moira.facade import (
planet_relative_to, next_heliocentric_transit,
PlanetPhenomena, planet_phenomena_at,
KeplerianElements, DistanceExtremes,
orbital_elements_at, distance_extremes_at,
)
| Function | Returns | Description |
|---|---|---|
planet_relative_to(body, center_body, jd_ut, reader=None) | PlanetData | Body position relative to another physical center body |
next_heliocentric_transit(body, target_lon, jd_start, reader=None, max_days=400.0) | float | Next heliocentric longitude crossing of a target longitude |
planet_phenomena_at(body, jd_ut) | PlanetPhenomena | Instantaneous elongation/phase-style observational summary for one body |
orbital_elements_at(body, jd_ut, reader) | KeplerianElements | Osculating orbital elements at one epoch |
distance_extremes_at(body, jd_ut, reader) | DistanceExtremes | Perihelion/aphelion-style distance-extrema summary at one epoch |
6. Alternative Reference Frames
Moira's default position products are geocentric ecliptic. Three additional engines surface different physical origins or light-cone geometry, each exposing true-of-date ecliptic orientation for direct comparison while preserving its own origin doctrine.
Solar System Barycenter (SSB) Chart
from moira.ssb import SSBPosition, SSB_BODIES, ssb_position_at, all_ssb_positions_at
The SSB is the true inertial center-of-mass of the solar system. The Sun wanders up to ~2.2 solar radii (~0.010 AU) from the SSB, driven mainly by Jupiter's mass. Positions use the SSB as origin and true-of-date ecliptic orientation (precession + nutation applied); they are not geocentric positions.
| Symbol | Type | Description |
|---|---|---|
SSB_BODIES | frozenset[str] | Bodies with well-defined barycentric state in DE441 |
ssb_position_at(body, jd_ut) | SSBPosition | SSB-relative position of one body |
all_ssb_positions_at(jd_ut) | dict[str, SSBPosition] | SSB-relative positions of all supported bodies |
SSBPosition fields
| Field | Type | Description |
|---|---|---|
name | str | Body name |
longitude | float | Ecliptic longitude (°), [0°, 360°) |
latitude | float | Ecliptic latitude (°) |
distance | float | Distance from SSB (km) |
speed | float | Longitudinal speed (°/day) |
retrograde | bool | True when speed < 0 |
sign | str | Zodiac sign (derived) |
sign_symbol | str | Sign glyph (derived) |
sign_degree | float | Degree within sign (derived) |
Property: distance_au → distance from SSB in Astronomical Units.
from moira.ssb import ssb_position_at, all_ssb_positions_at
from moira.facade import jd_from_datetime, utc_to_ut1
from datetime import datetime, timezone
jd = utc_to_ut1(jd_from_datetime(datetime(2000, 1, 1, 12, tzinfo=timezone.utc)))
sun_ssb = ssb_position_at("Sun", jd)
print(f"Sun from SSB: {sun_ssb.longitude:.4f}° dist {sun_ssb.distance_au:.6f} AU")
all_pos = all_ssb_positions_at(jd)
for name, pos in all_pos.items():
print(f"{name:10s} {pos.longitude:.4f}°")
Planetocentric Positions
from moira.planetocentric import (
PlanetocentricData, VALID_OBSERVER_BODIES,
planetocentric_at, all_planetocentric_at,
)
Geometric positions of celestial bodies measured from the center of a specified observer planet other than Earth. Any body with a barycentric state in the DE441 kernel can serve as the observer — including the Sun (heliocentric) and the Moon. Output preserves the requested observer-origin vector and uses true-of-date ecliptic orientation.
Valid observers: Body.SUN, Body.MOON, Body.MERCURY, Body.VENUS, Body.EARTH, Body.MARS, Body.JUPITER, Body.SATURN, Body.URANUS, Body.NEPTUNE, Body.PLUTO
| Symbol | Type | Description |
|---|---|---|
VALID_OBSERVER_BODIES | frozenset[str] | Bodies that may serve as observer or target |
planetocentric_at(observer, target, jd_ut) | PlanetocentricData | Position of target as seen from observer |
all_planetocentric_at(observer, jd_ut) | dict[str, PlanetocentricData] | All visible bodies from the observer |
PlanetocentricData fields
| Field | Type | Description |
|---|---|---|
observer | str | Observer body name |
name | str | Target body name |
longitude | float | Ecliptic longitude (°), [0°, 360°) |
latitude | float | Ecliptic latitude (°) |
distance | float | Observer–target distance (km) |
speed | float | Longitudinal speed (°/day) |
retrograde | bool | True when speed < 0 |
sign | str | Zodiac sign (derived) |
sign_symbol | str | Sign glyph (derived) |
sign_degree | float | Degree within sign (derived) |
Property: distance_au → observer–target distance in Astronomical Units.
from moira.planetocentric import planetocentric_at, all_planetocentric_at
# Saturn as seen from Jupiter:
sat_from_jup = planetocentric_at("Jupiter", "Saturn", jd)
# All planets as seen from Mars:
mars_sky = all_planetocentric_at("Mars", jd)
Received-Light (Light-Cone) Positions
from moira.light_cone import (
ReceivedLightPosition, RECEIVED_LIGHT_BODIES,
received_light_at, all_received_light_at,
)
Standard astrological positions already incorporate light-time correction (the body's position is computed for t − τ, where τ is the one-way light travel time). This engine makes the light-cone geometry explicit by surfacing both the apparent position (where the body was when it emitted the arriving light) and the geometric position (where the body physically is at the birth moment).
Typical light travel times and longitude displacements:
| Body | Light time | Max displacement |
|---|---|---|
| Moon | ~1.3 s | < 0.0001° |
| Sun | ~8.3 min | ~0.02° |
| Jupiter | ~35–52 min | ~0.06° |
| Saturn | ~68–84 min | ~0.10° |
| Pluto | ~5.3 h | ~0.35° |
| Symbol | Type | Description |
|---|---|---|
RECEIVED_LIGHT_BODIES | frozenset[str] | Physical bodies for which light-cone is meaningful (excludes computed points) |
received_light_at(body, jd_ut) | ReceivedLightPosition | Received-light position for one body |
all_received_light_at(jd_ut) | dict[str, ReceivedLightPosition] | Received-light positions for all supported bodies |
ReceivedLightPosition fields
| Field | Type | Description |
|---|---|---|
name | str | Body name |
apparent_longitude | float | Where body was when light emitted (°) — the standard astrological position |
apparent_latitude | float | Ecliptic latitude at emission instant (°) |
geometric_longitude | float | Where body physically is at birth moment (°) |
geometric_latitude | float | Ecliptic latitude at birth moment (°) |
distance_km | float | Earth–body distance at emission instant (km) |
light_travel_days | float | One-way light travel time (τ) in days |
emission_jd | float | Julian Date when photons were emitted (jd_ut − τ) |
speed | float | Apparent longitudinal speed (°/day) |
retrograde | bool | True when apparent speed < 0 |
sign | str | Sign of apparent longitude (derived) |
sign_symbol | str | Sign glyph (derived) |
sign_degree | float | Degree within sign (derived) |
Properties:
light_travel_minutes→ one-way light travel time in minuteslongitude_displacement→ angular shift between apparent and geometric longitude (°), in (−180°, +180°]distance_au→ Earth–body distance in Astronomical Units
from moira.light_cone import received_light_at, all_received_light_at
pluto = received_light_at("Pluto", jd)
print(f"Pluto apparent: {pluto.apparent_longitude:.4f}°")
print(f"Pluto geometric: {pluto.geometric_longitude:.4f}°")
print(f"Light travel: {pluto.light_travel_minutes:.1f} min")
print(f"Displacement: {pluto.longitude_displacement:+.4f}°")
7. Chart Structure
Houses
from moira.facade import calculate_houses, HouseCusps, HouseSystem
from moira.facade import (
assign_house, describe_boundary, describe_angularity,
compare_systems, compare_placements, distribute_points,
HouseSystemFamily, HouseSystemCuspBasis, HouseSystemClassification,
classify_house_system, HousePolicy,
HousePlacement, HouseBoundaryProfile,
HouseAngularity, HouseAngularityProfile,
HouseSystemComparison, HousePlacementComparison,
HouseOccupancy, HouseDistributionProfile,
)
| Function | Returns | Description |
|---|---|---|
calculate_houses(jd_ut, latitude, longitude, system=HouseSystem.PLACIDUS, *, policy=None, ayanamsa_offset=None) | HouseCusps | Compute house cusps and angles under explicit house policy when supplied |
assign_house(longitude, cusps) | HousePlacement | Find which house a longitude falls in |
describe_boundary(longitude, cusps, orb=2.0) | HouseBoundaryProfile | Proximity to house cusp boundaries |
describe_angularity(longitude, cusps, orb=5.0) | HouseAngularity | Angular/succedent/cadent classification |
compare_systems(jd_ut, latitude, longitude, systems) | HouseSystemComparison | Side-by-side comparison of multiple systems |
compare_placements(body_lon, systems_cusps) | HousePlacementComparison | How a body's house changes across systems |
distribute_points(longitudes, cusps) | HouseDistributionProfile | Count of points per house |
classify_house_system(system) | HouseSystemClassification | Family, cusp basis, polar behavior for a recognized code; raises ValueError on unknown codes |
House system families (HouseSystemFamily):
ECLIPTIC_BASED EQUATORIAL SPACE_BASED TIME_BASED EQUAL_HOUSE
UnknownSystemPolicy: controls behavior when an unrecognized house system is passed — RAISE (raises ValueError) or FALLBACK_TO_PLACIDUS (silently returns Placidus). Set via HousePolicy.
PolarFallbackPolicy: controls behavior at polar latitudes where certain systems are not supported by default — FALLBACK_TO_PORPHYRY, RAISE, or EXPERIMENTAL_SEARCH. The experimental mode is explicit and currently attempts branch-aware high-latitude Placidus only. Set via HousePolicy.
Aspects
from moira.facade import (
find_aspects, aspects_between, aspects_to_point,
aspects_from_longitudes,
find_declination_aspects, declination_aspects_from_declinations,
declination_aspect_motion_witness,
find_patterns, build_aspect_graph,
aspect_strength, aspect_motion_state, aspect_harmonic_profile,
AspectData, AspectPolicy, AspectStrength, DeclinationAspect,
DeclinationAspectAnalysis, LongitudeAspectAnalysis,
DeclinationAspectKind, DeclinationAspectMotionWitness,
DeclinationAspectPolicy, DeclinationMotionState,
AspectFamily, AspectDomain, AspectTier, MotionState,
AspectGraph, AspectGraphNode, AspectFamilyProfile, AspectHarmonicProfile,
CANONICAL_ASPECTS, DEFAULT_POLICY,
)
AspectData fields
| Field | Type | Description |
|---|---|---|
body1 | str | First body name |
body2 | str | Second body name |
aspect | str | Human name, e.g. "Conjunction", "Sextile" |
symbol | str | Glyph or short symbol for the aspect |
angle | float | Exact aspect angle in degrees, e.g. 0, 60, 90, 120, 180 |
separation | float | Actual angular separation between the bodies |
orb | float | Non-negative deviation from the exact aspect angle |
allowed_orb | float | Maximum allowed orb for this aspect |
applying | bool | None | Applying/separating truth; None when speeds are unavailable |
stationary | bool | True if a stationary motion state affects the aspect |
classification | AspectClassification | Domain, family, tier, motion state, and strength metadata |
direction | AspectDirection | None | Sinister/dexter casting direction from body1's perspective when defined |
hellenistic_superiority_truth | HellenisticSuperiorityTruth | None | Raw direction-applicability and whole-sign overcoming receipt for the ordered body pair |
sign_degree1 | int | None | Integer degree number within body1's sign, used for strict partile truth |
sign_degree2 | int | None | Integer degree number within body2's sign, used for strict partile truth |
Phase 3 introduced HellenisticAspectEvaluationStatus,
HellenisticOvercomingRelation, HellenisticDirectionTruth,
HellenisticOvercomingTruth, HellenisticSuperiorityTruth, and
hellenistic_superiority_truth() in moira.aspects.
AspectData.direction and overcoming() remain compatibility projections;
the aggregate receipt is the source of raw truth and carries no synthetic
score. Phase 4 forwards these exact objects through the root, classical, and
facade exports; Moira.hellenistic_superiority_truth() delegates without
recomputing or flattening the receipt.
AspectData convenience properties
| Property | Type | Description |
|---|---|---|
is_major | bool | True when the aspect belongs to the major Ptolemaic tier |
is_minor | bool | True when the aspect is not in the major tier |
is_zodiacal | bool | True when the aspect domain is zodiacal |
is_applying | bool | True only when applying is True |
is_separating | bool | True only when applying is False |
orb_surplus | float | Remaining orb headroom: allowed_orb - orb |
is_partile | bool | True when a major Ptolemaic aspect has both bodies in the same degree number of their signs |
is_platic | bool | True when a major Ptolemaic aspect is admitted but not partile |
Core aspect functions
| Function | Returns | Description |
|---|---|---|
find_aspects(longitudes, orbs=None, include_minor=True, speeds=None, tier=None, orb_factor=1.0, policy=None) | list[AspectData] | Low-level detector over a longitude dict with optional speed and policy inputs |
aspects_from_longitudes(longitudes, *, tier=1, orb_factor=1.0, include_nodes=True) | LongitudeAspectAnalysis | Validated first-class derived-position analysis; normalized deterministic inputs plus canonical AspectData results |
aspects_between(lons_a, lons_b, orbs=None, include_minor=True) | list[AspectData] | Cross-set aspects (synastry / transits) |
aspects_to_point(longitudes, point, orbs=None) | list[AspectData] | Aspects to a single longitude |
find_declination_aspects(bodies_dec, orb=1.0) | list[DeclinationAspect] | Parallel and contra-parallel aspects |
declination_aspects_from_declinations(bodies_dec, *, reference_frame, timescale, orb=1.0) | DeclinationAspectAnalysis | Validated deterministic caller-supplied declination analysis with explicit coordinate provenance |
declination_aspect_motion_witness(body1, dec1, body2, dec2, aspect, *, speed1_deg_per_day=None, speed2_deg_per_day=None, orb=1.0, exact_tolerance_deg=1e-9, rate_tolerance_deg_per_day=1e-12, reference_frame, timescale) | DeclinationAspectMotionWitness | Instantaneous signed declination error/rate witness for applying, exact, separating, stationary, or indeterminate truth |
build_aspect_graph(aspects) | AspectGraph | Graph structure of the aspect network |
aspect_strength(aspect) | AspectStrength | Geometric orb exactness, or categorical whole-sign exactness |
aspect_motion_state(aspect) | MotionState | APPLYING / EXACT / SEPARATING / STATIONARY / INDETERMINATE / NONE |
aspect_harmonic_profile(longitudes, harmonic) | AspectHarmonicProfile | Aspects visible at a given harmonic |
aspects_from_longitudes and LongitudeAspectAnalysis are exported from both
the curated package root and moira.facade. Moira.aspects_from_longitudes
is the equivalent facade method. The analysis records normalized longitudes,
the effective tier/orb multiplier, excluded engine node names, and
motion_semantics="not_computed_without_speeds". Its 355°/5° wrap separation
is 10°, and aspect admission remains inclusive at the applied orb boundary.
declination_aspects_from_declinations and DeclinationAspectAnalysis are
likewise exported from the package root and moira.facade, with
Moira.declination_aspects_from_declinations as the facade method. The
analysis records normalized declinations, the effective orb, and the
hemisphere-qualified Parallel/Contra-Parallel results. The caller must declare
the shared equatorial reference_frame and timescale; Moira records rather
than infers that provenance.
moira.declination_aspects is the governing module for these relationships.
moira.aspects retains compatibility re-exports and adapts the historical
AspectPolicy.declination_orb field to the new DeclinationAspectPolicy.
declination_aspect_motion_witness and
Moira.declination_aspect_motion_witness require declination rates to resolve
applying or separating state. A single declination snapshot without rates is
indeterminate unless already exact. Parallel motion uses the signed error
dec1 - dec2; Contra-Parallel motion uses dec1 + dec2. The witness is
instantaneous and does not claim future perfection before a reversal.
Aspect Patterns
from moira.facade import (
find_all_patterns, find_t_squares, find_grand_trines, find_grand_crosses,
find_yods, find_mystic_rectangles, find_kites, find_stelliums,
find_minor_grand_trines, find_grand_sextiles, find_thors_hammers,
find_boomerang_yods, find_wedges, find_cradles, find_trapezes,
find_eyes, find_irritation_triangles, find_hard_wedges,
find_dominant_triangles, find_grand_quintiles, find_quintile_triangles,
find_septile_triangles,
AspectPattern, PatternClassification,
)
The individual detectors accept their documented aspect list (or positions for
Stellium) and orb policy. They return list[AspectPattern].
find_all_patterns(longitudes, aspects=None, orb_factor=1.0, include=None, policy=None, dominant_only=False) runs the registered detectors in one call.
An explicit PatternComputationPolicy takes precedence over the legacy direct
policy arguments. Moira.patterns(chart, orb_factor=1.0, dominant_only=False) exposes the same opt-in containment choice.
With dominant_only=True, a smaller aspect pattern is removed only when its
body set and preserved aspect set are both contained in another admitted
aspect pattern, with at least one of those inclusions strict. For example, an
embedded Grand Trine is omitted when its Kite is admitted, and a same-body
Trapeze edge-subgraph is omitted when its Cradle is admitted. Equal-body
patterns with equal or incomparable edge sets remain; position-based Stelliums
retain their independent maximal-cluster doctrine.
AspectPattern fields
| Field | Type | Description |
|---|---|---|
name | str | Pattern name, e.g. "T-Square", "Grand Trine", "Yod" |
bodies | list[str] | Bodies participating in the pattern |
aspects | list[AspectData] | Aspects forming the pattern |
apex | str | None | Apex body (for Yods, T-Squares, etc.) |
classification | PatternClassification | Pattern classification metadata |
detection_truth | PatternDetectionTruth | Detection-trace metadata for the pattern |
all_contributions | list[PatternAspectContribution] | Full aspect/body contribution set |
contributions | list[PatternAspectContribution] | Primary contribution set used for display |
condition_profile | PatternConditionProfile | Consolidated pattern condition profile |
Pattern condition is structural role-resolution truth. reinforced means all
preserved aspect contributions have detector-owned roles, mixed means at
least one remains member_link, and weakened means there are no aspect
contributions. These states do not report aspect motion, exactness, harmony, or
interpretive strength. Grand Trine uses cycle_member/cycle_link; Minor
Grand Trine uses base/support; and Cradle/Trapeze use axis/support
roles without arbitrary left/right labels.
Chart shape (Jones types)
from moira.facade import classify_chart_shape, ChartShape, ChartShapeType
shape = classify_chart_shape(chart.longitudes(include_nodes=False))
# ChartShape(type, description, focal_point)
ChartShapeType constants: BUNDLE BOWL BUCKET LOCOMOTIVE FAN SEESAW SPLASH SPLAY
Midpoints
from moira.facade import calculate_midpoints, midpoints_to_point, Midpoint, MidpointsService
mps = calculate_midpoints(chart.longitudes(), orb=1.5)
# list[Midpoint(body1, body2, midpoint_lon, activated_by)]
hits = midpoints_to_point(chart.longitudes(), target_lon=15.0, orb=1.5)
# Using the service class for chained access:
svc = MidpointsService(chart.longitudes(), orb=1.5)
all_mps = svc.all() # list[Midpoint]
at_point = svc.to_point(15.0) # midpoints within orb of 15°
dial = svc.dial_90() # midpoints projected to 90° dial
tree = svc.tree(15.0) # midpoints equidistant from 15°
Harmonics
from moira.facade import (
HARMONIC_PRESETS,
HarmonicOrbPolicy,
HarmonicPosition,
HarmonicTransitSample,
MixedOriginHarmonicTransitForecastPolicy,
MixedOriginHarmonicTransitMode,
calculate_harmonic,
harmonic_conjunctions,
mixed_origin_harmonic_transit_forecast,
)
natal = chart.longitudes(include_nodes=False)
h55 = calculate_harmonic(natal, 5.5)
# list[HarmonicPosition]; 5.5 is preserved and is not truncated to 5
# The orb is the configurable H1 reference and the projected-chart limit.
orb_policy = HarmonicOrbPolicy(reference_orb_deg=1.0)
truth = orb_policy.resolve(5.5)
# truth.projected_orb_limit_deg == 1.0
# truth.source_orb_limit_deg == 1.0 / 5.5
hits = harmonic_conjunctions(natal, 5.5, orb_policy=orb_policy)
# Sampled VA-informed forecast: caller owns the transit positions and JDs.
samples = (
HarmonicTransitSample(2461000.0, {"Mars": 144.0, "Venus": 216.0}),
HarmonicTransitSample(2461000.5, {"Mars": 144.1, "Venus": 216.1}),
)
forecast_policy = MixedOriginHarmonicTransitForecastPolicy(
harmonics=(5, 7), # forecast harmonics remain positive integers
modes=(MixedOriginHarmonicTransitMode.ONE_TRANSIT_TWO_NATAL,),
orb_policy=orb_policy,
maximum_sample_gap_days=1.0,
)
forecast = mixed_origin_harmonic_transit_forecast(
natal,
samples,
forecast_policy,
)
HARMONIC_PRESETS is dict[int, tuple[str, str]], mapping an integer harmonic
to its descriptive name and summary, for example
{4: ("Square", "Tension, challenges, action"), ...}.
Direct single-harmonic projection, conjunction, score, and composite functions
accept any positive finite real H. Inputs are first reduced to the canonical
zero-Aries [0, 360) branch and then projected as
(normalized_longitude * H) mod 360. Integer H is the ordinary cyclic
harmonic; fractional H is an explicitly origin-anchored continuous multiplier.
Sweep, aspect-decoding, fingerprint, and transit-forecast harmonic collections
remain integer.
HarmonicOrbPolicy exposes the Addey inverse-H relation O_H = O_1/H without
double scaling. Its reference_orb_deg is applied as the projected harmonic
chart limit; HarmonicOrbTruth.source_orb_limit_deg reports the locally
equivalent source-circle allowance. The legacy positional orb remains
available as an adapter to this same H1-reference policy, but an engine call
may not supply both orb and orb_policy.
mixed_origin_harmonic_transit_forecast admits only complete triples containing
one transit plus two natal members or two transits plus one natal member. A
triple must fit inside one minimum circular covering arc. Returned window times
are first/peak/last supplied samples: the function neither interpolates nor
claims exact ingress, perfection, egress, or Sirius parity. See
HARMONIC_TRANSIT_FORECAST_STANDARD.md for the complete doctrine.
Antiscia
from moira.facade import find_antiscia, antiscia_to_point, AntisciaAspect
antiscia = find_antiscia(chart.longitudes(), orb=1.0)
# AntisciaAspect(body1, body2, kind, orb)
# kind: "antiscion" (solstice axis) or "contra-antiscion" (equinox axis)
Void of Course Moon
from moira.facade import (
void_of_course_window, is_void_of_course,
next_void_of_course, void_periods_in_range,
LastAspect, VoidOfCourseWindow,
)
voc = void_of_course_window(jd_ut)
# VoidOfCourseWindow(start_jd, end_jd, last_aspect, ingress_sign)
voc_periods = void_periods_in_range(jd_start, jd_end)
8. Classical Techniques
Dignities
from moira.facade import (
calculate_dignities, calculate_receptions,
calculate_condition_profiles, calculate_chart_condition_profile,
calculate_condition_network_profile,
PlanetaryDignity, EssentialDignityKind, AccidentalConditionKind,
DignitiesService,
sect_light, is_day_chart, almuten_figuris, find_phasis,
is_in_hayz, is_in_sect,
)
Quick helpers
| Function | Returns | Description |
|---|---|---|
is_day_chart(sun_lon, asc_lon) | bool | True if Sun is above the horizon (diurnal sect) |
sect_light(sun_lon, asc_lon) | str | "Sun" for day charts, "Moon" for night charts |
is_in_hayz(planet, sun_lon, asc_lon, chart_lons) | bool | True if planet is in hayz |
is_in_sect(planet, sun_lon, asc_lon) | bool | True if planet is in its preferred sect |
almuten_figuris(chart_lons, cusps, is_day) | str | Almuten figuris (planet with most dignities at ASC/MC/prenatal syzygy) |
find_phasis(body, jd_start, jd_end, reader=None) | list[float] | JDs of phasis (first/last visibility) for a body |
EssentialDignityKind values
DOMICILE EXALTATION TRIPLICITY TERM FACE DETRIMENT FALL PEREGRINE
AccidentalConditionKind values
DIRECT RETROGRADE STATIONARY ORIENTAL OCCIDENTAL CAZIMI COMBUST UNDER_BEAMS FREE_OF_BEAMS SWIFT SLOW IN_HAYZ OUT_OF_HAYZ
PlanetaryDignity fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
sign | str | Sign occupied by the planet |
degree | float | Degree within the sign |
house | int | House placement |
essential_dignity | EssentialDignityKind | Primary essential dignity/debility |
essential_score | int | Essential dignity score |
accidental_dignities | list[AccidentalDignityCondition] | Active accidental dignity conditions |
accidental_score | int | Accidental dignity score |
total_score | int | Combined dignity score |
is_retrograde | bool | Retrograde flag |
receptions | list[PlanetaryReception] | Active receptions involving the planet |
condition_profile | PlanetaryConditionProfile | Consolidated dignity/condition profile |
essential_truth | EssentialDignityTruth | Essential dignity computation truth data |
accidental_truth | AccidentalDignityTruth | Accidental dignity truth data |
sect_truth | SectTruth | Sect evaluation truth data |
solar_truth | SolarConditionTruth | Solar condition truth data |
all_receptions | list[PlanetaryReception] | Full reception set prior to filtering |
mutual_reception_truth | MutualReceptionTruth | Mutual reception truth data |
essential_classification | EssentialDignityClassification | Essential dignity classification metadata |
accidental_classification | AccidentalDignityClassification | Accidental dignity classification metadata |
sect_classification | SectClassification | Sect classification metadata |
solar_classification | SolarConditionClassification | Solar condition classification metadata |
reception_classification | ReceptionClassification | Reception classification metadata |
Condition profiles & networks
profiles = calculate_condition_profiles(chart_lons, house_cusps, is_day)
# list[PlanetaryConditionProfile]
chart_profile = calculate_chart_condition_profile(chart_lons, house_cusps, is_day)
# ChartConditionProfile
network = calculate_condition_network_profile(chart_lons, house_cusps, is_day)
# ConditionNetworkProfile — graph of planetary condition relationships
Phase 4 forwards the typed essential-component, solar-phase,
solar-proximity, besieging, horizon, Mercury-phase, and sect receipts through
the root, classical, facade, and Moira surfaces. REST serializers preserve
the same components with concrete OpenAPI models; policy suppression may
remove an assembled label or score contribution but does not erase available
raw geometry.
Unified Hellenistic chart profile
moira.hellenistic owns the Phase 5 non-interpretive composition surface.
The public function is also exported unchanged through moira,
moira.classical, and moira.facade.
from moira import HellenisticProfilePolicy, hellenistic_chart_profile
profile = hellenistic_chart_profile(
natal_positions,
natal_speeds,
whole_sign_cusps,
asc_longitude,
mc_longitude,
natal_dt,
current_dt,
policy=HellenisticProfilePolicy(),
observer_latitude=latitude,
observer_longitude=longitude,
observer_elevation_m=elevation_m,
position_frame=(
"apparent_geocentric_true_ecliptic_of_date_"
"positions_and_longitude_rates"
),
)
The raw function requires:
- all seven classical planets and one finite speed for each;
- twelve exact zodiac-boundary Whole Sign cusps;
- the actual Ascendant and Midheaven, distinct from Whole Sign cusp 1/10;
- timezone-aware natal and current datetimes, with current not before natal.
HellenisticChartProfile contains:
- score-free planetary essential components, sect, joy, solar proximity, solar phase, besieging, receptions, Dorothean triplicity, admitted bound, and Chaldean-face receipts;
- Whole Sign aspect classification and
HellenisticSuperiorityTruth; - Fortune, Spirit, Valens Eros, and Valens Necessity computation, dependency-completeness, and astrological-condition truth;
- annual profection plus typed activation truth;
- current Decennial L1/L2 periods with sequence-assembly truth;
- current Zodiacal Releasing periods for the selected foundational lot;
- included/excluded component registries and complete composition provenance.
The composer never infers a frame from observer coordinates alone. A raw or facade caller must label its supplied position/rate frame; otherwise provenance marks that frame unverified. The REST composition service constructs the seven classical planets through the default apparent-geocentric, true-ecliptic-of-date position and longitude-rate product. Observer coordinates are used independently for the strict Whole Sign house figure and exact angles.
There is no chart-wide score, ranking, recommendation, or interpretation. Atomic non-evaluable states survive composition. The explicit exclusions are Firdaria, medieval almutens, later electional rules, unscoped primary directions, Decennial L3/L4, Hermetic-decan geometry, Valens distribution interpretation, and Triacontaeteris. These are closed/out-of-contract boundaries rather than incomplete profile fields.
Moira.hellenistic_chart_profile() accepts a previously constructed Chart
and HouseCusps. It requires requested and effective Whole Sign systems with
no fallback, forwards exact angles, derives engine/kernel provenance when
available, and delegates to the owning function without recomputing doctrine.
Church of Light Natal Astrodynes
Astrodynes use a distinct Hermetic dignity table and must not be mixed with the
conventional dignities above. The full stable low-level surface lives in
moira.astrodynes; the root and facade expose the high-level constitutional
vessels and chart builder.
from moira import (
AstrodyneBodyInput,
AstrodynePolicy,
AstrodyneSummaryFamily,
AstrodyneSummaryProfile,
AstrodyneChartResult,
astrodynes_summary,
natal_astrodynes_from_geometry,
natal_astrodynes,
)
result = natal_astrodynes(
body_inputs, # ten planets plus M.C. and Asc.
cusp_signs, # twelve cusp signs in house order
intercepted_signs_by_house={2: ("Gemini",)},
)
| Surface | Returns | Description |
|---|---|---|
natal_astrodynes(body_inputs, cusp_signs, *, intercepted_signs_by_house=None, policy=None) | AstrodyneChartResult | Full natal profiles, relations, aggregates, Class 5 summaries, network, and checksum truth |
natal_astrodynes_from_geometry(planet_longitudes, declinations, cusp_longitudes, mc_longitude, asc_longitude, *, policy=None) | AstrodyneChartResult | Derive body inputs, houses, interpolation geometry, cusp signs, and interceptions from a complete explicit tropical figure |
astrodynes_summary(aggregate) | AstrodyneSummaryProfile | Society, trinity, element, and quality partitions of an existing chart aggregate |
validate_astrodynes_output(result) | tuple[str, ...] | Deterministic cross-layer invariant failures |
Moira.astrodynes(...) | AstrodyneChartResult | Kernel-free facade delegate |
Moira.astrodynes_from_geometry(...) | AstrodyneChartResult | Kernel-free explicit-geometry facade delegate |
AstrodyneBodyInput preserves longitude, optional declination, house number,
house class, and the house-interpolation geometry required by the manual.
Full-chart assembly requires the ten planets plus M.C. and Asc..
Principal result layers:
| Type | Meaning |
|---|---|
AstrodyneRelationSet | Detected, admitted, and scored zodiacal, parallel, and mutual-reception relations |
AstrodyneBodyConditionProfile | Integrated power, harmony, discord, dignity, and named contributions for one body |
AstrodyneSignAggregate | Average-ruler share plus occupants for one sign |
AstrodyneHouseAggregate | Cusp/interception ruler shares plus house occupants |
AstrodyneChartAggregate | Twelve signs, twelve houses, and sign/house checksums |
AstrodyneSummaryEntry | One named Class 5 group with members, power, percentage, and harmony/discord truth |
AstrodyneSummaryProfile | Society, trinity, element, and quality families over one chart total |
AstrodyneNetwork | Nodes aligned with body profiles and edges aligned with admitted relations |
AstrodyneChartResult | Policy, inputs, relations, profiles, aggregate, summary, and network |
The only admitted AstrodynePolicy is the confirmed Church of Light doctrine:
one-degree exaltation/fall emphasis, 60-arcminute magnitude parallels,
Mercury's ordinary presence orb plus luminary scoring orb, and a +5 mutual
reception bonus. Unsupported alternatives raise ValueError.
See ASTRODYNES_BACKEND_STANDARD for the full doctrine, constitutional layers, invariants, and validation boundary.
Arabic Parts / Lots
from moira.facade import (
calculate_lots, evaluate_lots,
calculate_lot_dependencies, calculate_all_lot_dependencies,
calculate_lot_condition_profiles, calculate_lot_chart_condition_profile,
calculate_lot_condition_network_profile,
ArabicPart, LotsEvaluation, LotNotEvaluable,
ArabicPartsService, list_parts, LotReversalKind,
)
| Function | Returns | Description |
|---|---|---|
calculate_lots(lons, cusps, is_day, *, asc_longitude=None, mc_longitude=None, ...) | list[ArabicPart] | All classical Arabic Parts; explicit angles are authoritative when supplied |
evaluate_lots(lons, cusps, is_day, *, asc_longitude=None, mc_longitude=None, ...) | LotsEvaluation | Computed parts plus typed not_evaluable catalogue entries; explicit angles remain distinct from house cusps |
list_parts() | list[str] | Names of all available parts |
ArabicPart fields
| Field | Type | Description |
|---|---|---|
name | str | Part name, e.g. "Fortune", "Spirit" |
longitude | float | Ecliptic longitude (degrees) |
formula | str | Formula used to derive the part |
category | str | Part category/classification label |
description | str | Short textual description |
computation_truth | ArabicPartComputationTruth | Truth data for the part computation |
classification | ArabicPartClassification | Classification metadata |
all_dependencies | list[LotDependency] | Full dependency graph slice for the part |
dependencies | list[LotDependency] | Direct dependencies used by the part |
dependency_completeness | LotDependencyCompletenessTruth | Separate dependency-resolution receipt |
astrological_condition_truth | LotAstrologicalConditionTruth | Separate condition boundary; currently not_evaluable without admitted doctrine |
condition_profile | LotConditionProfile | Computed condition profile |
sign | str | Sign occupied by the part |
sign_symbol | str | Sign glyph/symbol |
sign_degree | float | Degree within the sign |
Using ArabicPartsService
svc = ArabicPartsService(lons, cusps, is_day)
fortune = svc.fortune() # ArabicPart
spirit = svc.spirit()
exalt = svc.exaltation()
Phase 4 makes evaluate_lots and its aggregate/status vessels identical
objects across root, classical, and facade imports, with
Moira.evaluate_lots() as the chart-backed delegate. The REST chart route
uses this lossless aggregate and never treats an unresolved entry as an
evaluated absence.
Profections
from moira.facade import (
annual_profection, monthly_profection, profection_chronology,
profection_schedule, LeapDayAnniversaryPolicy,
MonthlyProfectionIntervalPolicy, ProfectionAmbiguousTimePolicy,
ProfectionResult,
)
result = profection_schedule(
natal_asc_lon,
natal_dt,
current_dt,
civil_timezone="America/New_York",
activation_orb=0.75,
leap_day_policy=LeapDayAnniversaryPolicy.FEBRUARY_28,
)
# result.age_years, result.profected_house, result.lord_of_year
| Function | Returns | Description |
|---|---|---|
annual_profection(natal_asc, age_years, natal_positions=None, activation_orb=5.0) | ProfectionResult | Whole-sign annual profection for an explicit completed age |
monthly_profection(natal_asc, age_years, month_index) | tuple[float, str, str] | Monthly subdivision for an explicit age and month index |
profection_chronology(natal_asc, natal_dt, current_dt, *, civil_timezone=None, leap_day_policy=None, ambiguous_time_policy=None, interval_policy=...) | ProfectionChronology | Exact civil-anniversary anchors and twelve engine-owned dated monthly intervals |
profection_schedule(natal_asc, natal_dt, current_dt, natal_positions=None, *, civil_timezone=None, leap_day_policy=None, ambiguous_time_policy=None, interval_policy=..., activation_orb=5.0) | ProfectionResult | Civil-anniversary age, activation truth, and query-specific monthly chronology |
Both chronology functions require timezone-aware datetimes and reject
pre-birth instants. REST-normalized UTC callers should supply an authoritative
IANA civil_timezone; the exact timezone-data source and version are preserved
in the receipt. February 29 nativities require an explicit february_28 or
march_1 policy. A repeated local anniversary requires explicit
earlier_occurrence or later_occurrence; no fold is guessed.
The admitted interval policy divides the exact elapsed UTC duration between
consecutive local civil anniversaries into twelve contiguous, half-open
intervals whose lengths differ by at most one microsecond. The method is
explicitly classified as a computational projection. It is not fixed 30-day
arithmetic, a 365.25-day quotient, civil-calendar months, or Valens IV.28's
separate luminary-distance method. annual_profection() has no query
chronology and returns chronology=None.
Phase 3 introduced ProfectionActivationStatus,
ProfectionActivationBodyTruth, ProfectionActivationTruth, and
profection_activation_truth() in moira.profections.
ProfectionResult.activation_truth distinguishes absent natal positions
(not_evaluable, reason="natal_positions_not_supplied") from an explicitly
supplied empty mapping and from an evaluated chart with no activations. The
legacy activated_planets list is derived from evaluated raw truth and remains
empty in all three cases. Phase 4 forwards those names through root,
classical, and facade, adds the raw Moira helper, and preserves
activation_orb through Moira.profection(), schedule service composition,
REST serialization, and OpenAPI.
Nakshatras (Vedic lunar mansions)
from moira.facade import nakshatra_of, all_nakshatras_at, NakshatraPosition
pos = nakshatra_of(moon_longitude, jd_ut, ayanamsa_system=Ayanamsa.LAHIRI)
# NakshatraPosition(name, number, pada, lord, remaining_fraction)
all_naks = all_nakshatras_at(chart.longitudes(include_nodes=False), jd_ut)
# dict[str, NakshatraPosition]
Arabic Lunar Mansions (Manazil)
from moira.facade import mansion_of, all_mansions_at, moon_mansion, MansionPosition, MANSIONS
pos = mansion_of(moon_longitude)
# MansionPosition(number, name, start_lon, end_lon, ruling_planet)
moon_man = moon_mansion(moon_longitude) # same, convenience alias
all_m = all_mansions_at(chart.longitudes())
MANSIONS: tuple of 28 MansionInfo entries.
Longevity (Hyleg / Alcocoden)
from moira.facade import find_hyleg, calculate_longevity, HylegResult
hyleg = find_hyleg(chart_lons, cusps, is_day)
# HylegResult(hyleg, alcocoden, projected_years)
result = calculate_longevity(chart_lons, cusps, is_day)
print(result.projected_years)
Gauquelin sectors
See Section 4 (Ephemeris & Positions).
Planetary Hours (moira.planetary_hours)
from moira.facade import planetary_hours, PlanetaryHoursDay, PlanetaryHour
day = planetary_hours(jd_ut, latitude, longitude, reader=None)
# PlanetaryHoursDay(date, day_hours: list[PlanetaryHour], night_hours: list[PlanetaryHour])
# PlanetaryHour(ruler, start_jd, end_jd)
Note: This is
moira.planetary_hours.PlanetaryHour. A distinct vessel,moira.cycles.PlanetaryHour, is documented in Section 10 with additional fields (hour_number,is_day_hour). The two classes serve different engines and must not be conflated.
Varga (Vedic divisional charts)
from moira.facade import calculate_varga, navamsa, saptamsa, dashamansa, dwadashamsa, trimshamsa
d9 = navamsa(longitude) # D9 — ninth division
d7 = saptamsa(longitude) # D7 — seventh division
d10 = dashamansa(longitude) # D10 — tenth division
d12 = dwadashamsa(longitude) # D12 — twelfth division
d30 = trimshamsa(longitude) # D30 — thirtieth division
# Generic:
pos = calculate_varga(longitude, divisor=9)
# VargaPoint(divisor, position_in_sign, sign_number, sign_name)
Decanates
from moira.facade import chaldean_face, triplicity_decan, vedic_drekkana, DecanatePosition
face = chaldean_face(longitude)
trip = triplicity_decan(longitude)
d3 = vedic_drekkana(longitude, jd, ayanamsa_system=Ayanamsa.LAHIRI)
| Function | Returns | Description |
|---|---|---|
chaldean_face(longitude) | DecanatePosition | Classical Chaldean face for a tropical longitude |
triplicity_decan(longitude) | DecanatePosition | Western triplicity decan for a tropical longitude |
vedic_drekkana(longitude, jd, ayanamsa_system=Ayanamsa.LAHIRI) | DecanatePosition | Vedic D3 drekkana for a sidereally normalized longitude |
DecanatePosition fields
| Field | Type | Description |
|---|---|---|
system | str | Decan system name: chaldean_face, triplicity, or vedic_drekkana |
decan_number | int | Decan number within the sign, 1-3 |
ruling_planet | str | Planetary ruler of the decan |
ruling_sign | str | None | Governing sign for triplicity or Vedic drekkana; None for Chaldean face |
sign | str | Zodiac sign containing the longitude used |
sign_symbol | str | Zodiac sign glyph/symbol |
degree_in_decan | float | Degrees elapsed within the 10° decan span |
longitude_used | float | Longitude actually classified after any required normalization |
Hermetic Decans — Research-Only Closed Product Exclusion
The names, sign order, planetary faces, and source pages in
moira.hermetic_decans are reconstructed from Gundel's 1936 edition of the
Harley MS 3731 list. The source supports Aries-starting 10-degree segmentation;
the module's modern tropical-frame and rising projections remain unadmitted,
and the unsupported fixed-star table fails closed. The former decan_hours()
experiment and its result vessels have been removed. Nothing from this module
is exported from moira or moira.facade; direct import remains a research
surface, not part of the supported Python API contract.
This is a completed boundary, not unfinished Hellenistic engine work.
9. Timing Techniques
Transits
from moira.facade import (
find_transits, next_transit, find_ingresses, next_ingress, next_ingress_into,
solar_return, lunar_return, planet_return,
last_new_moon, last_full_moon, prenatal_syzygy,
transit_relations, ingress_relations,
transit_condition_profiles, ingress_condition_profiles,
transit_chart_condition_profile, transit_condition_network_profile,
TransitEvent, IngressEvent, TransitSearchPolicy, TransitComputationPolicy,
)
TransitEvent fields
| Field | Type | Description |
|---|---|---|
body | str | Transiting body |
longitude | float | Exact longitude of the event |
jd_ut | float | JD UT of the exact transit |
direction | str | Search direction / crossing direction |
computation_truth | TransitComputationTruth | Search/computation truth data |
classification | TransitComputationClassification | Transit classification metadata |
relation | TransitRelation | Target relation metadata |
condition_profile | TransitConditionProfile | Transit condition profile |
IngressEvent fields
| Field | Type | Description |
|---|---|---|
body | str | Body entering the sign |
sign | str | Sign entered |
jd_ut | float | JD UT of the ingress |
direction | str | Ingress direction |
computation_truth | IngressComputationTruth | Search/computation truth data |
classification | IngressComputationClassification | Ingress classification metadata |
relation | TransitRelation | Sign-ingress relation metadata |
condition_profile | TransitConditionProfile | Ingress condition profile |
Core functions
events = find_transits(Body.SATURN, natal_sun_lon, jd_start, jd_end, reader=reader)
ev = next_transit(Body.JUPITER, natal_moon_lon, jd_now, reader=reader)
ingr = find_ingresses(Body.SATURN, jd_start, jd_end, reader=reader)
next_i = next_ingress(Body.JUPITER, jd_now, reader=reader)
into = next_ingress_into(Body.SATURN, "Aquarius", jd_now, reader=reader)
jd_sr = solar_return(natal_sun_lon, year=2025, reader=reader)
jd_lr = lunar_return(natal_moon_lon, jd_now, reader=reader)
jd_pr = planet_return(Body.JUPITER, natal_jup_lon, jd_now, reader=reader)
jd_nm = last_new_moon(jd_now, reader=reader)
jd_fm = last_full_moon(jd_now, reader=reader)
jd_syn, kind = prenatal_syzygy(jd_natal, reader=reader)
Stations & Retrograde
from moira.facade import find_stations, next_station, is_retrograde, retrograde_periods, StationEvent
stations = find_stations(Body.MARS, jd_start, jd_end, reader=reader)
# StationEvent(jd, body, kind) kind: "retrograde" | "direct"
retro_intervals = retrograde_periods(Body.MERCURY, jd_start, jd_end, reader=reader)
# list[(jd_start, jd_end)]
Progressions & Directions
All progression functions share the signature:
(jd_natal, target_dt, bodies=None, reader=None) → ProgressedChart
from moira.facade import (
secondary_progression, solar_arc, solar_arc_right_ascension,
naibod_longitude, naibod_right_ascension,
tertiary_progression, tertiary_ii_progression,
minor_progression, ascendant_arc, daily_houses,
converse_secondary_progression, converse_solar_arc,
converse_solar_arc_right_ascension,
converse_naibod_longitude, converse_naibod_right_ascension,
converse_tertiary_progression, converse_tertiary_ii_progression,
converse_minor_progression,
ProgressedChart, ProgressedPosition,
ProgressionTimeKeyPolicy, ProgressionDirectionPolicy,
ProgressionComputationPolicy,
)
| Technique | Function | Key rate |
|---|---|---|
| Secondary Progression | secondary_progression | 1 day = 1 year |
| Solar Arc | solar_arc | Sun's progressed daily motion applied to all bodies |
| Solar Arc (RA) | solar_arc_right_ascension | Solar Arc in right ascension |
| Naibod (longitude) | naibod_longitude | 0°59′08″/year |
| Naibod (RA) | naibod_right_ascension | Naibod in right ascension |
| Tertiary | tertiary_progression | 1 day = 1 lunar month |
| Tertiary II | tertiary_ii_progression | Klaus Wessel variant |
| Minor | minor_progression | 1 lunar month = 1 year |
| Ascendant Arc | ascendant_arc | ASC arc applied to all bodies |
All converse variants (moving backward) are prefixed with converse_.
ProgressedChart fields
| Field | Type | Description |
|---|---|---|
chart_type | str | Progression technique identifier |
natal_jd_ut | float | Natal JD UT |
progressed_jd_ut | float | Progressed JD UT used for the positions |
target_date | datetime | Target date requested by the user |
solar_arc_deg | float | Solar arc applied when relevant |
positions | dict[str, ProgressedPosition] | Body → progressed position |
computation_truth | ProgressionComputationTruth | Progression computation truth data |
classification | ProgressionComputationClassification | Progression classification metadata |
relation | ProgressionRelation | Relation metadata for natal/progressed comparison |
condition_profile | ProgressionConditionProfile | Consolidated progression profile |
ProgressedPosition: longitude, latitude, speed, natal_longitude.
Primary Directions
from moira.facade import speculum, find_primary_arcs, SpeculumEntry, PrimaryArc, DIRECT, CONVERSE
spec = speculum(chart, houses, geo_lat=51.5)
arcs = find_primary_arcs(chart, houses, geo_lat=51.5, max_arc=90.0, include_converse=True)
# list[PrimaryArc(significator, promissor, arc, direction, method, space,
# motion, solar_rate, relational_kind)]
# arc.years() → years by key "naibod" (default)
# arc.years("ptolemy") → years by Ptolemy key
# arc.solar_rate_explicit → whether solar_rate is natal/generated provenance
PrimaryArc.relational_kind is the actual positional relation. Relation
profiles retain the historical relation_kind field for perfection kind and
provide perfection_kind as its explicit alias. The solar key is a static
conversion by one explicit positive natal solar rate; it is not a dynamic
integration and fails closed without that rate. For compatibility,
PrimaryArc.solar_rate remains numeric when a caller omits the rate, but
solar_rate_explicit is then False and solar-key conversion does not treat
that value as natal provenance. Engine-generated arcs and explicitly supplied
rates report True.
Method/space capability is enforced: PLACIDUS_MUNDANE and
PLACIDIAN_CLASSIC_SEMI_ARC are not accepted with IN_ZODIACO.
Placidian-classic geometry uses the equatorial horizon identity
OA(ASC) = (ARMC + 90 degrees) mod 360. Fixed-star targets require
conjunction admission, while rapt-parallel motion remains specific to the
configured rapt relation/target. Aspectual points sourced from a house cusp
materialize that cusp before projection. Supplied Morinus aspect contexts are
normalized and unique by exact source identity.
Relation vessels bind perfection kind to the arc's space. Relation profiles must contain relations owned by their stated arc, and significator profiles preserve arc/profile order one-for-one. The method, perfection, relation, and target ordered transition-network vessels additionally require a connected, degree-valid Euler path or lawfully linearizable circuit; aggregate counts alone cannot attest a possible sequence.
Firdaria (Persian Time Lords)
from moira.facade import (
firdaria, current_firdaria, group_firdaria,
firdar_condition_profile, firdar_sequence_profile, firdar_active_pair,
validate_firdaria_output,
FirdarPeriod, FirdarMajorGroup, FirdarConditionProfile,
FirdarSequenceProfile, FirdarActivePair,
FirdarSequenceKind, FirdarYearPolicy, TimelordComputationPolicy,
DEFAULT_TIMELORD_POLICY,
FIRDARIA_DIURNAL, FIRDARIA_NOCTURNAL, FIRDARIA_NOCTURNAL_BONATTI,
CHALDEAN_ORDER, MINOR_YEARS,
)
| Function | Returns | Description |
|---|---|---|
firdaria(jd_natal, is_day, policy=None) | list[FirdarPeriod] | Full Firdaria sequence from birth |
current_firdaria(jd_natal, jd_now, is_day, policy=None) | FirdarPeriod | Active Firdaria period at jd_now |
group_firdaria(periods) | list[FirdarMajorGroup] | Periods grouped by major lord |
firdar_condition_profile(period, chart_lons) | FirdarConditionProfile | Condition analysis for one period |
firdar_sequence_profile(jd_natal, is_day, jd_now) | FirdarSequenceProfile | Full condition profile across sequence |
firdar_active_pair(jd_natal, jd_now, is_day) | FirdarActivePair | Major + minor lord pair at jd_now |
FirdarPeriod fields (moira.timelords)
This is
moira.timelords.FirdarPeriod. A distinct vessel,moira.cycles.FirdarPeriod, is documented in Section 10 with different fields (ruler,start_jd,end_jd,duration_years,ordinal,sub_periods). The two classes serve different engines and must not be conflated.
| Field | Type | Description |
|---|---|---|
level | int | Period level |
planet | str | Active period lord |
start_jd | float | Start JD |
end_jd | float | End JD |
years | float | Duration in years |
major_planet | str | Parent major lord |
is_day_chart | bool | True for diurnal sect sequence |
variant | str | Variant used for the sequence |
sequence_kind | FirdarSequenceKind | Sequence family metadata |
is_node_period | bool | Whether the period belongs to the nodal sequence |
Decennials
from moira.facade import (
decennials, current_decennials, group_decennials,
decennial_condition_profile, decennial_sequence_profile,
decennial_active_pair, decennial_active_path,
validate_decennials_output,
DecennialPeriod, DecennialPolicy, DecennialTimeBasis,
)
| Function | Returns | Description |
|---|---|---|
decennials(jd_natal, natal_positions, is_day_chart, levels=2, policy=None) | list[DecennialPeriod] | Admitted L1/L2 sequence from the sect light |
current_decennials(..., jd_now, levels=2, policy=None) | tuple[DecennialPeriod, DecennialPeriod] | Active major and L2 period |
group_decennials(periods) | list[DecennialMajorGroup] | Major periods with their L2 children |
decennial_active_path(periods, jd) | DecennialActivePath | None | Active admitted L1/L2 lineage |
Phase 3 introduced TimelordEvaluationStatus,
DecennialSequenceBodyTruth, DecennialSequenceAssemblyTruth, and
decennial_sequence_truth() in moira.timelords. The assembly
receipt preserves the Classic 7 dependency geometry and fails closed on a
non-sect-light longitude tie instead of using private planet order. Every
generated period carries the same evaluated sequence_truth. Phase 4 forwards
the exact raw types/function through root, classical, facade, and Moira, and
serializes the receipt on every REST period with a concrete OpenAPI schema.
The public engine accepts only levels 1–2. Any L3/L4 request or non-None
DecennialPolicy.deep_subdivision_method fails closed; the named Valens and
Hephaistio deep policies are closed exclusions, not admitted API behavior or
release backlog. The REST request schema exposes no deep-method selector.
Every period preserves time_basis, calendar_projection_basis,
sequence_origin_jd, start_distribution_day, end_distribution_day, and
distribution_years. start_jd/end_jd are elapsed-day projections from the
natal instant; they do not mean that schematic 30-day months were added as
civil calendar months.
Zodiacal Releasing
from moira.facade import (
zodiacal_releasing, current_releasing, group_releasing,
zr_condition_profile, zr_sequence_profile, zr_level_pair,
validate_releasing_output,
ReleasingPeriod, ZRPeriodGroup, ZRConditionProfile,
ZRSequenceProfile, ZRLevelPair,
ZRAngularityClass, ZRYearPolicy,
)
| Function | Returns | Description |
|---|---|---|
zodiacal_releasing(lot_lon, jd_natal, levels=4, *, lot_name="Spirit", fortune_longitude=None, use_loosing_of_bond=True, policy=None) | list[ReleasingPeriod] | Full ZR sequence with explicit Lot, Fortune, bond, and time-basis policy |
current_releasing(lot_lon, jd_natal, jd_now, fortune_longitude=None) | list[ReleasingPeriod] | Active period at each available level; rejects the exact 211-symbolic-year endpoint and later |
group_releasing(periods) | list[ZRPeriodGroup] | Grouped by Level 1 sign |
zr_level_pair(lot_lon, jd_natal, jd_now) | ZRLevelPair | Active Level 1 + Level 2 pair |
zr_sequence_profile(periods, level) rejects an empty input and a requested
level absent from the generated period list. REST callers must keep
profile_level <= levels.
ReleasingPeriod fields
| Field | Type | Description |
|---|---|---|
level | int | Period level (1-4) |
sign | str | Releasing sign |
ruler | str | Sign ruler |
start_jd | float | Start JD |
end_jd | float | End JD |
years | float | Period length in years |
lot_name | str | Lot used for the releasing sequence |
is_loosing_of_bond | bool | Whether the period begins with a Loosing of the Bond |
is_peak_period | bool | True only in places 1, 4, 7, or 10 from Fortune |
angularity_from_fortune | int | None | Inclusive place 1–12 from Fortune; None when Fortune is omitted |
use_loosing_of_bond | bool | Whether Loosing of the Bond is enabled |
angularity_class | ZRAngularityClass | None | Angular / succedent / cadent class; None only when Fortune is omitted |
fortune_angularity_truth | ZRFortuneAngularityTruth | None | Raw Fortune dependency, place, class, and peak receipt |
zr_fortune_angularity_truth() and ZRFortuneAngularityTruth are direct
moira.timelords Phase 3 surfaces. With no Fortune, raw status is
not_evaluable and raw peak truth is None; the legacy
ReleasingPeriod.is_peak_period projection remains False. Phase 4 forwards
the raw helper/type through root, classical, facade, and Moira; every REST
period now carries the typed Fortune-angularity receipt.
Vimshottari Dasha
from moira.facade import (
vimshottari, current_dasha, dasha_balance,
dasha_active_line, dasha_condition_profile, dasha_sequence_profile,
dasha_lord_pair, validate_vimshottari_output,
DashaPeriod, DashaActiveLine, DashaConditionProfile,
DashaSequenceProfile, DashaLordPair, DashaLordType,
VimshottariComputationPolicy, DEFAULT_VIMSHOTTARI_POLICY,
VIMSHOTTARI_YEARS, VIMSHOTTARI_SEQUENCE, VIMSHOTTARI_TOTAL,
VIMSHOTTARI_YEAR_BASIS, VIMSHOTTARI_LEVEL_NAMES,
)
| Function | Returns | Description |
|---|---|---|
vimshottari(moon_tropical_lon, natal_jd, levels=2, ayanamsa_system=None, *, year_basis=None, policy=None) | list[DashaPeriod] | Full Vimshottari sequence |
current_dasha(moon_tropical_lon, natal_jd, current_jd, ayanamsa_system=None, *, year_basis=None, levels=5, policy=None) | list[DashaPeriod] | One active period per generated level |
dasha_balance(moon_tropical_lon, natal_jd, ayanamsa_system=None, *, year_basis=None, policy=None) | tuple[str, float] | Natal Mahadasha lord and remaining balance in Vimshottari years |
dasha_active_line(active_periods) | DashaActiveLine | Named active chain from the list returned by current_dasha |
dasha_condition_profile(period) | DashaConditionProfile | Condition profile for one generated period |
dasha_sequence_profile(periods) | DashaSequenceProfile | Aggregate profile for a generated sequence |
dasha_lord_pair(line) | DashaLordPair | Mahadasha + Antardasha lords from a DashaActiveLine |
DashaPeriod fields
| Field | Type | Description |
|---|---|---|
level | int | 1 = Mahadasha, 2 = Antardasha, 3 = Pratyantardasha |
planet | str | Dasha lord (planet name) |
start_jd | float | Start JD |
end_jd | float | End JD |
year_days | float | Duration expressed in days/year-basis units |
sub | list[DashaPeriod] | Nested sub-periods (if levels > 1) |
year_basis | str | Year basis used for the sequence |
birth_nakshatra | str | Natal Moon nakshatra |
nakshatra_fraction | float | Fraction of nakshatra elapsed at birth |
lord_type | DashaLordType | Lord classification metadata |
VIMSHOTTARI_YEARS: dict of lord → years (Ketu=7, Venus=20, Sun=6, ...).
Ashtottari & Yogini Dasha
from moira import (
ashtottari, yogini_dasha,
AlternateDashaPeriod, AlternatePeriodProfile, AlternateDashaSequenceProfile,
AshtottariPolicy, YoginiPolicy,
validate_alternate_dasha_output,
)
| Function | Returns | Description |
|---|---|---|
ashtottari(moon_tropical_lon, natal_jd, levels=2, policy=None) | list[AlternateDashaPeriod] | Full Ashtottari dasha sequence |
yogini_dasha(moon_tropical_lon, natal_jd, levels=2, policy=None) | list[AlternateDashaPeriod] | Full Yogini dasha sequence |
alternate_period_profile(period) | AlternatePeriodProfile | Inspect one alternate-dasha period |
alternate_sequence_profile(periods) | AlternateDashaSequenceProfile | Aggregate profile for an alternate-dasha sequence |
validate_alternate_dasha_output(periods) | None | Validate alternate-dasha output structure |
AlternateDashaPeriod fields
| Field | Type | Description |
|---|---|---|
system | str | Dasha system name |
level | int | Period level within the nested sequence |
lord | str | Period lord |
start_jd | float | Start JD |
end_jd | float | End JD |
sub | list[AlternateDashaPeriod] | Nested sub-periods |
AlternatePeriodProfile fields
| Field | Type | Description |
|---|---|---|
system | str | Dasha system name |
level | int | Period level |
lord | str | Period lord name |
planet | str | Normalized planetary identity of the lord |
years | float | Nominal period length in years |
is_node_lord | bool | True when the lord is a node |
is_luminary_lord | bool | True when the lord is Sun or Moon |
AlternateDashaSequenceProfile fields
| Field | Type | Description |
|---|---|---|
system | str | Dasha system name |
total_years | int | Total sequence span in years |
mahadasha_count | int | Number of top-level periods |
profiles | list[AlternatePeriodProfile] | Profile for each Mahadasha lord |
Alternate Dasha policy & constants
| Public symbol | Kind | Description |
|---|---|---|
AshtottariPolicy | dataclass | year_basis, ayanamsa_system, bypass_eligibility, lagna_sign_index |
YoginiPolicy | dataclass | year_basis, ayanamsa_system |
ASHTOTTARI_YEARS | dict[str, int] | Ashtottari lord → years table |
ASHTOTTARI_SEQUENCE | tuple[str, ...] | Ashtottari lord order |
ASHTOTTARI_NAKSHATRA_LORD | dict[int, str] | Nakshatra-index → Ashtottari lord mapping |
ASHTOTTARI_TOTAL | int | Total Ashtottari cycle years |
YOGINI_YEARS | dict[str, int] | Yogini lord → years table |
YOGINI_SEQUENCE | tuple[str, ...] | Yogini lord order |
YOGINI_PLANETS | dict[str, str] | Yogini name → planetary identity mapping |
YOGINI_TOTAL | int | Total Yogini cycle years |
Panchanga
from moira import (
panchanga_at, tithi_condition_profile, panchanga_profile,
PanchangaResult, TithiConditionProfile, PanchangaProfile, PanchangaPolicy,
TithiPaksha, YogaClass, KaranaType, VaraLordType,
validate_panchanga_output,
)
| Function | Returns | Description |
|---|---|---|
panchanga_at(sun_tropical_lon, moon_tropical_lon, jd, ayanamsa_system=Ayanamsa.LAHIRI, policy=None) | PanchangaResult | Compute tithi, nakshatra, yoga, karana, and vara for a moment |
tithi_condition_profile(result) | TithiConditionProfile | Tithi waxing/waning and condition profile |
panchanga_profile(result) | PanchangaProfile | Aggregate Panchanga condition summary |
validate_panchanga_output(result) | None | Validate Panchanga result invariants |
PanchangaResult fields
| Field | Type | Description |
|---|---|---|
jd | float | Julian day of the computation moment |
tithi | PanchangaElement | Tithi element |
vara | PanchangaElement | Weekday element |
vara_lord | str | Planetary lord of the weekday |
nakshatra | object | Nakshatra result for the Moon |
yoga | PanchangaElement | Yoga element |
karana | PanchangaElement | Karana element |
ayanamsa_system | str | Governing ayanamsa system |
TithiConditionProfile fields
| Field | Type | Description |
|---|---|---|
tithi_name | str | Tithi name |
tithi_index | int | Zero-based tithi index |
tithi_number | int | Traditional tithi number |
paksha | str | Waxing or waning half |
is_purnima | bool | True at Full Moon tithi |
is_amavasya | bool | True at New Moon tithi |
degrees_elapsed | float | Degrees elapsed within the tithi |
degrees_remaining | float | Degrees remaining in the tithi |
PanchangaProfile fields
| Field | Type | Description |
|---|---|---|
jd | float | Julian day of the computation moment |
paksha | str | Waxing or waning half |
is_purnima | bool | Full Moon flag |
is_amavasya | bool | New Moon flag |
yoga_class | str | Classified yoga family |
karana_type | str | Classified karana family |
vara_lord | str | Weekday lord |
vara_lord_type | str | Benefic/malefic or related lord classification |
ayanamsa_system | str | Governing ayanamsa system |
PanchangaElement fields
| Field | Type | Description |
|---|---|---|
name | str | Element name |
index | int | Zero-based element index |
number | int | Traditional 1-based element number |
degrees_elapsed | float | Degrees elapsed within the element |
degrees_remaining | float | Degrees remaining in the element |
Panchanga policy & constants
| Public symbol | Kind | Description |
|---|---|---|
PanchangaPolicy | dataclass | ayanamsa_system |
TithiPaksha | enum-like class | SHUKLA, KRISHNA |
YogaClass | enum-like class | AUSPICIOUS, INAUSPICIOUS |
KaranaType | enum-like class | MOVABLE, FIXED |
VaraLordType | enum-like class | LUMINARY, INNER, OUTER |
TITHI_NAMES | tuple[str, ...] | Traditional tithi names |
YOGA_NAMES | tuple[str, ...] | Traditional yoga names |
KARANA_NAMES | tuple[str, ...] | Traditional karana names |
VARA_LORDS | tuple[str, ...] | Weekday lord sequence |
VARA_NAMES | tuple[str, ...] | Weekday names |
Jaimini Karakas
from moira import (
jaimini_karakas, atmakaraka, karaka_condition_profile,
jaimini_chart_profile, karaka_pair,
JaiminiKarakaResult, KarakaConditionProfile, JaiminiChartProfile, KarakaPair,
JaiminiPolicy, validate_jaimini_output,
)
| Function | Returns | Description |
|---|---|---|
jaimini_karakas(sidereal_longitudes, scheme=7, policy=None) | JaiminiKarakaResult | Assign Jaimini karaka roles from sidereal longitudes |
atmakaraka(sidereal_longitudes, scheme=7) | str | Planet holding the Atmakaraka role |
karaka_condition_profile(assignment, scheme) | KarakaConditionProfile | Inspect one karaka assignment in context |
jaimini_chart_profile(result) | JaiminiChartProfile | Aggregate Jaimini karaka chart profile |
karaka_pair(result, role_a, role_b) | KarakaPair | Compare two named karaka roles |
validate_jaimini_output(result) | None | Validate Jaimini assignment output |
JaiminiKarakaResult fields
| Field | Type | Description |
|---|---|---|
assignments | list[KarakaAssignment] | Ordered karaka assignments |
scheme | int | 7- or 8-karaka assignment scheme |
atmakaraka | str | Planet holding the Atmakaraka role |
tie_warnings | list[tuple[str, str]] | Tie diagnostics emitted during assignment |
KarakaConditionProfile fields
| Field | Type | Description |
|---|---|---|
karaka_name | str | Karaka role name |
karaka_rank | int | Positional rank in the assignment order |
planet | str | Assigned planet |
planet_type | str | Planet or node type classification |
degree_in_sign | float | Degrees traversed within the sign |
sidereal_longitude | float | Full sidereal longitude |
is_rahu_inverted | bool | True when Rahu inversion governs the assignment |
is_atmakaraka | bool | True for the Atmakaraka |
is_darakaraka | bool | True for the Darakaraka |
JaiminiChartProfile fields
| Field | Type | Description |
|---|---|---|
scheme | int | 7- or 8-karaka assignment scheme |
atmakaraka_planet | str | Atmakaraka planet |
darakaraka_planet | str | Darakaraka planet |
has_node_atmakaraka | bool | True when a node becomes Atmakaraka |
has_node_darakaraka | bool | True when a node becomes Darakaraka |
has_ties | bool | True when assignment ties were detected |
tie_count | int | Number of tie warnings |
profiles | list[KarakaConditionProfile] | Per-role diagnostic profiles |
KarakaPair fields
| Field | Type | Description |
|---|---|---|
role_a | str | First requested role |
role_b | str | Second requested role |
planet_a | str | Planet assigned to the first role |
planet_b | str | Planet assigned to the second role |
type_a | str | Type classification for the first role holder |
type_b | str | Type classification for the second role holder |
involves_node | bool | True when either role holder is a node |
both_are_nodes | bool | True when both role holders are nodes |
KarakaAssignment fields
| Field | Type | Description |
|---|---|---|
karaka_name | str | Assigned karaka role |
karaka_rank | int | Role rank in the ordered assignment |
planet | str | Assigned planet |
degree_in_sign | float | Degrees traversed within the sign |
sidereal_longitude | float | Full sidereal longitude |
is_rahu_inverted | bool | True when Rahu inversion governs the assignment |
Jaimini policy & enums
| Public symbol | Kind | Description |
|---|---|---|
JaiminiPolicy | dataclass | scheme, ayanamsa_system |
KarakaRole | enum-like class | Atmakaraka through Darakaraka role constants |
KarakaPlanetType | enum-like class | LUMINARY, INNER, OUTER, NODE |
KARAKA_NAMES_7 | tuple[str, ...] | Canonical 7-karaka role sequence |
KARAKA_NAMES_8 | tuple[str, ...] | Canonical 8-karaka role sequence |
Vedic Dignities
from moira import (
vedic_dignity, planetary_relationships,
dignity_condition_profile, chart_dignity_profile,
VedicDignityResult, PlanetaryRelationship,
DignityConditionProfile, ChartDignityProfile, VedicDignityPolicy,
validate_dignity_output,
)
| Function | Returns | Description |
|---|---|---|
vedic_dignity(planet, sidereal_longitude) | VedicDignityResult | Compute exaltation, debilitation, own-sign, and Mulatrikona condition |
planetary_relationships(sidereal_longitudes) | list[PlanetaryRelationship] | Natural/compound relationship diagnostics across a chart |
dignity_condition_profile(result) | DignityConditionProfile | Inspect one Vedic dignity result |
chart_dignity_profile(dignity_results) | ChartDignityProfile | Aggregate chart-level dignity profile |
validate_dignity_output(result) | None | Validate Vedic dignity output invariants |
VedicDignityResult fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
sidereal_longitude | float | Sidereal longitude used for evaluation |
sign_index | int | Zero-based sidereal sign index |
sign | str | Sidereal sign name |
dignity_rank | str | Resulting dignity rank |
is_exalted | bool | Exaltation flag |
is_debilitated | bool | Debilitation flag |
is_mulatrikona | bool | Mulatrikona flag |
is_own_sign | bool | Own-sign flag |
exaltation_score | float | Continuous exaltation-strength score |
PlanetaryRelationship fields
| Field | Type | Description |
|---|---|---|
from_planet | str | Source planet |
to_planet | str | Target planet |
natural | str | Natural relationship |
temporary | str | Temporary relationship |
compound | str | Combined relationship result |
DignityConditionProfile fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
dignity_rank | str | Dignity rank |
tier | str | Interpreted dignity tier |
exaltation_score | float | Exaltation-strength score |
sign_index | int | Sign index |
sign | str | Sign name |
ChartDignityProfile fields
| Field | Type | Description |
|---|---|---|
strong_count | int | Count of strong dignities |
neutral_count | int | Count of neutral dignities |
weak_count | int | Count of weak dignities |
strongest_planet | str | Strongest planet by dignity tier |
weakest_planet | str | Weakest planet by dignity tier |
planet_tiers | dict[str, str] | Planet-to-tier mapping |
exaltation_scores | dict[str, float] | Planet-to-exaltation-score mapping |
Vedic dignity policy, enums, and constants
| Public symbol | Kind | Description |
|---|---|---|
VedicDignityPolicy | dataclass | ayanamsa_system |
VedicDignityRank | enum-like class | EXALTATION, MULATRIKONA, OWN_SIGN, FRIEND_SIGN, NEUTRAL_SIGN, ENEMY_SIGN, DEBILITATION |
CompoundRelationship | enum-like class | GREAT_FRIEND, FRIEND, NEUTRAL, ENEMY, GREAT_ENEMY |
DignityTier | enum-like class | STRONG, NEUTRAL, WEAK |
EXALTATION_SIGN | dict[str, int] | Planet → exaltation sign index |
EXALTATION_DEGREE | dict[str, float] | Planet → deepest exaltation degree |
DEBILITATION_SIGN | dict[str, int] | Planet → debilitation sign index |
MULATRIKONA_SIGN | dict[str, int] | Planet → Mulatrikona sign index |
MULATRIKONA_START | dict[str, float] | Planet → Mulatrikona start degree |
MULATRIKONA_END | dict[str, float] | Planet → Mulatrikona end degree |
OWN_SIGNS | dict[str, tuple[int, ...]] | Planet → own-sign indices |
NATURAL_FRIENDS | dict[str, tuple[str, ...]] | Planet → natural friends |
NATURAL_NEUTRALS | dict[str, tuple[str, ...]] | Planet → natural neutrals |
NATURAL_ENEMIES | dict[str, tuple[str, ...]] | Planet → natural enemies |
Ashtakavarga
from moira import (
bhinnashtakavarga, ashtakavarga,
sign_strength_profile, transit_strength, ashtakavarga_chart_profile,
BhinnashtakavargaResult, AshtakavargaResult,
SignStrengthProfile, AshtakavargaChartProfile, AshtakavargaPolicy,
validate_ashtakavarga_output,
)
| Function | Returns | Description |
|---|---|---|
bhinnashtakavarga(planet, sign_indices) | BhinnashtakavargaResult | Per-planet rekha distribution across the 12 signs |
ashtakavarga(sidereal_longitudes, ayanamsa_system=None, policy=None) | AshtakavargaResult | Full Sarvashtakavarga and Bhinnashtakavarga result |
sign_strength_profile(bhinna, sign_idx, policy=None) | SignStrengthProfile | Interpret one sign within a Bhinnashtakavarga result |
transit_strength(planet, transit_sign_index, bhinna) | int | Rekha strength of a transit through a sign |
ashtakavarga_chart_profile(result, policy=None) | AshtakavargaChartProfile | Aggregate Ashtakavarga chart profile |
validate_ashtakavarga_output(result) | None | Validate Ashtakavarga output invariants |
BhinnashtakavargaResult fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
rekhas | tuple[int, ...] | 12-sign rekha vector |
total_rekhas | int | Sum of rekhas across all signs |
AshtakavargaResult fields
| Field | Type | Description |
|---|---|---|
ayanamsa_system | str | Governing ayanamsa system |
bhinnashtakavarga | dict[str, BhinnashtakavargaResult] | Per-planet bhinna results |
sarvashtakavarga | tuple[int, ...] | Aggregate 12-sign Sarvashtakavarga vector |
shodhana_bhinnashtakavarga | dict[str, BhinnashtakavargaResult] | None | Shodhana-adjusted bhinna results when enabled |
shodhana_sarvashtakavarga | tuple[int, ...] | None | Shodhana-adjusted Sarvashtakavarga when enabled |
SignStrengthProfile fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
sign_idx | int | Zero-based sign index |
rekha_count | int | Rekha count in the sign |
tier | str | Strength tier under the active policy |
AshtakavargaChartProfile fields
| Field | Type | Description |
|---|---|---|
sarva_total | int | Total Sarvashtakavarga points |
sarva_max | int | Maximum sign score |
sarva_max_sign_idx | int | Sign index of the maximum score |
sarva_min | int | Minimum sign score |
sarva_min_sign_idx | int | Sign index of the minimum score |
strong_planet_sign_counts | dict[str, int] | Count of strong signs by planet |
ayanamsa_system | str | Governing ayanamsa system |
Ashtakavarga policy & constants
| Public symbol | Kind | Description |
|---|---|---|
AshtakavargaPolicy | dataclass | ayanamsa_system, strong_threshold, apply_trikona_shodhana, apply_ekadhipatya_shodhana |
RekhaTier | enum-like class | Strength-tier constants for rekha interpretation |
REKHA_TABLES | dict[str, dict[str, tuple[int, ...]]] | Classical rekha tables used to build Bhinnashtakavarga |
Shadbala
from moira import (
sthana_bala, dig_bala, kala_bala, chesta_bala, drig_bala,
shadbala, hora_lord_at,
shadbala_condition_profile, shadbala_chart_profile,
PlanetShadbala, ShadbalaResult, ShadbalaConditionProfile, ShadbalaChartProfile,
ShadbalaPolicy, validate_shadbala_output,
)
| Function | Returns | Description |
|---|---|---|
sthana_bala(planet, sidereal_lon, houses, jd, ayanamsa_system=Ayanamsa.LAHIRI) | SthanaBala | Positional strength components for one planet |
dig_bala(planet, sidereal_lon, houses, jd, ayanamsa_system=Ayanamsa.LAHIRI) | float | Directional strength for one planet |
kala_bala(planet, sidereal_lon, sun_sidereal_lon, jd, tithi_number, is_day, vara_lord, planet_speeds, hora_lord=None, ayanamsa_system=Ayanamsa.LAHIRI, local_day_frac=None) | KalaBala | Temporal strength components for one planet |
chesta_bala(planet, speed, planet_sidereal_lon=None, mandoccha_sidereal_lon=None) | float | Motional strength for one planet |
drig_bala(planet, sidereal_longitudes) | float | Aspect-based strength contribution for one planet |
shadbala(sidereal_longitudes, planet_speeds, houses, jd, tithi_number, vara_lord, is_day, ayanamsa_system=Ayanamsa.LAHIRI, hora_lord=None, planet_latitudes=None) | ShadbalaResult | Full Shadbala computation for the seven classical planets |
hora_lord_at(birth_jd, sunrise_jd) | str | Planetary hora lord at birth |
shadbala_condition_profile(planet_result) | ShadbalaConditionProfile | Inspect one planet’s Shadbala result |
shadbala_chart_profile(result) | ShadbalaChartProfile | Aggregate chart-level Shadbala profile |
validate_shadbala_output(result) | None | Validate Shadbala output invariants |
PlanetShadbala fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
sthana_bala | SthanaBala | Positional strength components |
dig_bala | float | Directional strength |
kala_bala | KalaBala | Temporal strength components |
chesta_bala | float | Motional strength |
naisargika_bala | float | Natural strength constant |
drig_bala | float | Aspect-based strength |
total_shashtiamsas | float | Total strength in shashtiamsas |
total_rupas | float | Total strength in rupas |
required_rupas | float | Required threshold for sufficiency |
is_sufficient | bool | Sufficiency flag |
ShadbalaResult fields
| Field | Type | Description |
|---|---|---|
jd | float | Julian day of the computation moment |
ayanamsa_system | str | Governing ayanamsa system |
planets | dict[str, PlanetShadbala] | Per-planet Shadbala results |
ShadbalaConditionProfile fields
| Field | Type | Description |
|---|---|---|
planet | str | Planet name |
tier | str | Interpreted strength tier |
total_rupas | float | Total strength in rupas |
required_rupas | float | Required threshold |
strength_ratio | float | Ratio of actual to required strength |
is_sufficient | bool | Sufficiency flag |
ShadbalaChartProfile fields
| Field | Type | Description |
|---|---|---|
sufficient_count | int | Count of planets meeting the threshold |
insufficient_count | int | Count of planets below threshold |
strongest_planet | str | Strongest planet by ratio |
weakest_planet | str | Weakest planet by ratio |
planet_tiers | dict[str, str] | Planet-to-tier mapping |
strength_ratios | dict[str, float] | Planet-to-ratio mapping |
ayanamsa_system | str | Governing ayanamsa system |
SthanaBala fields
| Field | Type | Description |
|---|---|---|
uchcha | float | Exaltation-proximity component |
saptavargaja | float | Seven-varga dignity component |
ojayugma | float | Odd/even sign-parity component |
kendradi | float | Angularity component |
drekkana | float | Decan-gender component |
total | float | Total positional strength |
KalaBala fields
| Field | Type | Description |
|---|---|---|
nathonnatha | float | Day/night strength component |
paksha | float | Lunar-phase strength component |
tribhaga | float | Third-of-day/night component |
abda_masa_vara_hora | float | Year/month/weekday/hour-lord component |
ayana | float | Solstitial component |
yuddha | float | Planetary-war bonus component |
total | float | Total temporal strength |
Shadbala policy, tiers, and constants
| Public symbol | Kind | Description |
|---|---|---|
ShadbalaPolicy | dataclass | ayanamsa_system |
ShadbalaTier | enum-like class | SUFFICIENT, INSUFFICIENT |
NAISARGIKA_BALA | dict[str, float] | Natural fixed-strength constants in shashtiamsas |
REQUIRED_RUPAS | dict[str, float] | Required sufficiency thresholds in rupas |
MEAN_DAILY_MOTION | dict[str, float] | Mean daily motion constants used in Chesta Bala |
10. Planetary Cycles Engine
from moira.cycles import (
# Enums
SynodicPhase, GreatMutationElement, PlanetaryAgeName,
# Return series
ReturnEvent, ReturnSeries,
return_series, half_return_series, lifetime_returns,
# Synodic cycles
SynodicCyclePosition, synodic_cycle_position,
# Great conjunctions
GreatConjunction, GreatConjunctionSeries, MutationPeriod,
great_conjunctions, mutation_period_at,
# Planetary ages
PlanetaryAgePeriod, PlanetaryAgeProfile,
planetary_age_at, planetary_age_profile,
# Firdar
FirdarPeriod, FirdarSubPeriod, FirdarSeries,
firdar_series, firdar_at,
# Planetary days and hours
PlanetaryDayInfo, PlanetaryHour, PlanetaryHoursProfile,
planetary_day_ruler, planetary_hours_for_day,
)
moira.cycles governs cyclical timing frameworks grounded in astronomical periodicity. It is distinct from moira.timelords (Firdaria, Zodiacal Releasing, Vimshottari) and moira.transits (sign ingresses, transit events). The cycles engine focuses on the long-arc structure of planetary time: returns, synodic phases, the Jupiter–Saturn great conjunction doctrine, and Ptolemaic planetary ages.
Return Series
A complete series of returns (or half-returns) for one body across a date range.
| Function | Returns | Description |
|---|---|---|
return_series(body, natal_lon, jd_start, jd_end) | ReturnSeries | All direct returns of a body to its natal longitude |
half_return_series(body, natal_lon, jd_start, jd_end) | ReturnSeries | Returns and half-returns (oppositions) interleaved |
lifetime_returns(body, natal_lon, jd_natal, age_years=90.0) | ReturnSeries | Full-lifetime return sequence from birth |
ReturnEvent fields
| Field | Type | Description |
|---|---|---|
body | str | The returning body |
return_number | int | Ordinal (1 = first return) |
jd_ut | float | JD UT of exact return |
longitude | float | Natal longitude returned to (°) |
is_half | bool | True for a half-return (opposition to natal) |
ReturnSeries fields
| Field | Type | Description |
|---|---|---|
body | str | Body name |
natal_longitude | float | Natal longitude (°) |
jd_start | float | Start of search window |
jd_end | float | End of search window |
returns | tuple[ReturnEvent, ...] | All returns, chronological |
count | int | Number of returns found |
Synodic Cycles
pos = synodic_cycle_position(body1, body2, jd_ut)
# SynodicCyclePosition
SynodicCyclePosition fields
| Field | Type | Description |
|---|---|---|
body1 | str | First body |
body2 | str | Second body |
jd_ut | float | Moment of evaluation |
phase_angle | float | Phase angle from body1 to body2 (°), [0°, 360°) — 0° = conjunction |
phase | SynodicPhase | Eight-fold phase classification |
is_waxing | bool | True if the phase angle is increasing (0°–180°) |
lon1 | float | Ecliptic longitude of body1 at evaluation (°) |
lon2 | float | Ecliptic longitude of body2 at evaluation (°) |
SynodicPhase values: NEW WAXING_CRESCENT FIRST_QUARTER WAXING_GIBBOUS FULL WANING_GIBBOUS LAST_QUARTER WANING_CRESCENT
SynodicPhase.from_angle(angle_deg) classifies an arbitrary phase angle into one of the eight phases.
Great Conjunctions
The Jupiter–Saturn 20/200/800-year conjunction doctrine (Abu Ma'shar, Kepler).
| Function | Returns | Description |
|---|---|---|
great_conjunctions(jd_start, jd_end) | GreatConjunctionSeries | All Jupiter–Saturn conjunctions in a range |
mutation_period_at(longitude) | GreatMutationElement | Elemental trigon (FIRE / EARTH / AIR / WATER) for a given ecliptic longitude |
GreatConjunction fields
| Field | Type | Description |
|---|---|---|
jd_ut | float | JD UT of exact conjunction |
longitude | float | Conjunction longitude (°) |
sign | str | Zodiac sign name |
sign_symbol | str | Zodiac sign glyph |
degree_in_sign | float | Degree within the sign |
element | GreatMutationElement | Elemental trigon: FIRE / EARTH / AIR / WATER |
GreatMutationElement values: FIRE EARTH AIR WATER
GreatConjunctionSeries fields
| Field | Type | Description |
|---|---|---|
jd_start | float | Start of search window |
jd_end | float | End of search window |
conjunctions | tuple[GreatConjunction, ...] | All conjunctions found, chronological |
count | int | Number of conjunctions |
elements_represented | tuple[GreatMutationElement, ...] | Distinct elements present, in order of first occurrence |
MutationPeriod fields
| Field | Type | Description |
|---|---|---|
element | GreatMutationElement | Dominant element for this ~200-year period |
start_conjunction | GreatConjunction | First conjunction that inaugurated this element period |
end_conjunction | GreatConjunction | None | Final conjunction in this element before mutation (None if period extends beyond the search window) |
conjunction_count | int | Number of conjunctions in this element during this period |
Planetary Ages (Ptolemy)
The seven-age model from Tetrabiblos I.10. Each planet governs a developmental stage.
| Function | Returns | Description |
|---|---|---|
planetary_age_at(age_years) | PlanetaryAgePeriod | Which planet governs a given age |
planetary_age_profile(age_years=None) | PlanetaryAgeProfile | Full seven-period model; pass age_years to identify the current period |
PlanetaryAgePeriod fields
| Field | Type | Description |
|---|---|---|
ruler | PlanetaryAgeName | Governing planet |
start_age | float | Age when this period begins (years) |
end_age | float | None | Age when this period ends (None for Saturn, which is open-ended) |
label | str | Human-readable stage label (e.g. "Childhood", "Prime") |
PlanetaryAgeName values: MOON MERCURY VENUS SUN MARS JUPITER SATURN
Standard Ptolemaic durations: Moon 0–4, Mercury 4–14, Venus 14–22, Sun 22–41, Mars 41–56, Jupiter 56–68, Saturn 68+.
PlanetaryAgeProfile fields
| Field | Type | Description |
|---|---|---|
periods | tuple[PlanetaryAgePeriod, ...] | All seven age periods in order |
current | PlanetaryAgePeriod | None | Active period for the queried age, or None if not queried |
queried_age | float | None | The age that was queried (years), or None |
Firdar (cycles.py variant)
moira.cycles provides a streamlined Firdar engine. It is distinct from moira.timelords.firdaria, which adds condition profiles and reception network analysis on top of the same foundation.
Diurnal sequence (day births): Sun(10) → Venus(8) → Mercury(13) → Moon(9) → Saturn(11) → Jupiter(12) → Mars(7) → North Node(3) → South Node(2) = 75 years
Nocturnal sequence (night births): Moon(9) → Saturn(11) → Jupiter(12) → Mars(7) → Sun(10) → Venus(8) → Mercury(13) → North Node(3) → South Node(2) = 75 years
| Function | Returns | Description |
|---|---|---|
firdar_series(jd_natal, is_day) | FirdarSeries | Complete 75-year Firdar sequence from birth |
firdar_at(jd_natal, jd_now, is_day) | FirdarPeriod | Active Firdar period (major + sub) at jd_now |
FirdarSeries fields
| Field | Type | Description |
|---|---|---|
birth_jd | float | Birth Julian Day |
is_day_birth | bool | True for diurnal nativity |
periods | tuple[FirdarPeriod, ...] | All 9 firdar major periods in sequence |
total_years | float | Sum of all periods (~75 Julian years) |
FirdarPeriod fields (cycles.py vessel)
| Field | Type | Description |
|---|---|---|
ruler | str | The planet (or node) governing this firdar |
start_jd | float | Start JD UT of the major period |
end_jd | float | End JD UT |
duration_years | float | Duration in Julian years |
ordinal | int | Position in the sequence (1–9) |
sub_periods | tuple[FirdarSubPeriod, ...] | None | 7 planetary sub-periods (None for nodal firdars) |
FirdarSubPeriod fields
| Field | Type | Description |
|---|---|---|
sub_ruler | str | Governing planet for the sub-period |
start_jd | float | Start JD UT |
end_jd | float | End JD UT |
duration_years | float | Duration in Julian years |
Planetary Days and Hours
| Function | Returns | Description |
|---|---|---|
planetary_day_ruler(jd_ut) | PlanetaryDayInfo | Chaldean day ruler for the given JD |
planetary_hours_for_day(jd_ut, latitude, longitude) | PlanetaryHoursProfile | Full day and night planetary hour schedule |
PlanetaryDayInfo fields
| Field | Type | Description |
|---|---|---|
ruler | str | Planet ruling this day (Chaldean order) |
weekday_name | str | Name of the weekday |
weekday_number | int | ISO weekday (1 = Monday, 7 = Sunday) |
PlanetaryHour fields
| Field | Type | Description |
|---|---|---|
hour_number | int | 1–24 (1–12 = day hours, 13–24 = night hours) |
ruler | str | Planet governing this hour |
start_jd | float | Start of this hour (JD UT) |
end_jd | float | End of this hour (JD UT) |
is_day_hour | bool | True for a daytime (diurnal) hour |
PlanetaryHoursProfile fields
| Field | Type | Description |
|---|---|---|
day_info | PlanetaryDayInfo | The day's ruler and weekday metadata |
sunrise_jd | float | Sunrise JD used for the day's hours |
sunset_jd | float | Sunset JD used |
next_sunrise_jd | float | Next sunrise JD (used for nighttime hour duration) |
hours | tuple[PlanetaryHour, ...] | All 24 hours in order (1–24) |
day_hour_length | float | Duration of one daytime hour (days) |
night_hour_length | float | Duration of one nighttime hour (days) |
11. Huber Method
from moira.huber import (
HouseZone,
PHI, PHI_COMPLEMENT, CYCLE_YEARS, YEARS_PER_HOUSE,
HouseZoneProfile, AgePointPosition, DynamicIntensity,
PlanetIntensityScore, ChartIntensityProfile,
house_zones, age_point, age_point_contacts,
dynamic_intensity, intensity_at, chart_intensity_profile,
)
The Huber symbols are also available via the cumulative tier modules:
moira.classical,moira.predictive, andmoira.facade. Themoira.huberimport path is the direct low-level surface; the tier modules re-export the same symbols.
Implements the computational apparatus of the Huber method (Bruno and Louise Huber, Astrological Psychology Institute). Koch houses are prescribed by Huber doctrine; all functions accept any HouseCusps but note the doctrinal preference.
Constants
| Constant | Value | Description |
|---|---|---|
PHI | 0.6180... | Golden ratio fractional part |
PHI_COMPLEMENT | 0.3819... | Complement of phi (1 − phi) |
CYCLE_YEARS | 72.0 | Full Age Point cycle in years |
YEARS_PER_HOUSE | 6.0 | Years the Age Point spends per house |
HouseZone — golden-section zones
Each house is divided by the golden ratio into three developmental zones:
| Zone | Fraction | Quality |
|---|---|---|
CARDINAL | 0.000 – 0.382 | Outward initiative, environmental engagement |
FIXED | 0.382 – 0.618 | Consolidation, stable expression |
MUTABLE | 0.618 – 1.000 | Transition, preparation for the next house |
House Zone Analysis
zones = house_zones(houses)
# list[HouseZoneProfile] — one per house
HouseZoneProfile fields
| Field | Type | Description |
|---|---|---|
house | int | House number (1–12) |
cusp_longitude | float | Opening cusp longitude (°) |
next_cusp_longitude | float | Next cusp longitude (°) |
house_size | float | Angular size of the house (°) |
balance_point_longitude | float | Balance Point longitude (cusp + 0.382 × size) |
low_point_longitude | float | Low Point longitude (cusp + 0.618 × size) |
balance_point_fraction | float | Always PHI_COMPLEMENT (~0.382) |
low_point_fraction | float | Always PHI (~0.618) |
Age Point
ap = age_point(houses, jd_natal, jd_now)
# AgePointPosition
The Age Point progresses counterclockwise through the 12 houses over 72 years (6 years per house), starting from the Ascendant.
AgePointPosition fields
| Field | Type | Description |
|---|---|---|
age_years | float | Age in years from birth |
cycle | int | Which 72-year cycle (1 = first life, 2 = second…) |
house | int | House number currently occupied (1–12) |
fraction_through_house | float | 0.0 at cusp, 1.0 at next cusp |
longitude | float | Ecliptic longitude of the Age Point (°) |
zone | HouseZone | CARDINAL / FIXED / MUTABLE zone |
years_into_house | float | Years elapsed since entering this house |
intensity | float | Dynamic Intensity Curve value (0.0–1.0) |
contacts = age_point_contacts(houses, jd_natal, jd_now, chart_longitudes, orb=2.0)
# list of bodies the Age Point is conjunct within orb
Dynamic Intensity Curve
di = dynamic_intensity(houses, longitude)
# DynamicIntensity(house, zone, fraction, intensity)
score = intensity_at(houses, longitude)
# float in [0.0, 1.0] — 1.0 at any cusp, minimum at the Low Point
Chart Intensity Profile
profile = chart_intensity_profile(houses, planet_longitudes)
# ChartIntensityProfile
Scores all natal planets against the Dynamic Intensity Curve and produces a chart-level summary.
ChartIntensityProfile fields
| Field | Type | Description |
|---|---|---|
scores | list[PlanetIntensityScore] | Per-planet scores, highest first |
mean_intensity | float | Mean intensity across all scored planets |
dominant_planet | str | Planet with the highest intensity score |
dominant_zone | HouseZone | Zone of the dominant planet |
PlanetIntensityScore: planet, longitude, house, zone, fraction_through_house, intensity.
from moira.huber import house_zones, age_point, chart_intensity_profile
from moira.facade import Moira, HouseSystem
from datetime import datetime, timezone
m = Moira()
dt_birth = datetime(1988, 4, 4, 14, 30, tzinfo=timezone.utc)
dt_now = datetime(2026, 4, 7, tzinfo=timezone.utc)
# Koch houses (Huber doctrine)
houses = m.houses(dt_birth, latitude=51.5, longitude=-0.1, system=HouseSystem.KOCH)
chart = m.chart(dt_birth)
zones = house_zones(houses)
ap = age_point(houses, chart.jd_ut, m.jd(2026, 4, 7))
profile = chart_intensity_profile(houses, chart.longitudes())
print(f"Age Point: House {ap.house} ({ap.zone.value}), intensity {ap.intensity:.2f}")
print(f"Dominant planet: {profile.dominant_planet}")
12. Relational Techniques
Synastry
from moira.facade import (
synastry_aspects, synastry_contacts,
house_overlay, mutual_house_overlays,
synastry_contact_relations, mutual_overlay_relations,
synastry_condition_profiles, synastry_chart_condition_profile,
synastry_condition_network_profile,
SynastryHouseOverlay, MutualHouseOverlay,
SynastryAspectTruth, SynastryAspectContact,
SynastryOverlayTruth, SynastryRelation,
SynastryConditionState, SynastryConditionProfile,
SynastryChartConditionProfile,
SynastryConditionNetworkProfile,
SynastryAspectPolicy, SynastryOverlayPolicy,
SynastryComputationPolicy,
)
| Function | Returns | Description |
|---|---|---|
synastry_aspects(chart_a, chart_b, tier=2, orbs=None, orb_factor=1.0, include_nodes=True) | list[AspectData] | Inter-chart aspects |
synastry_contacts(chart_a, chart_b, ...) | list[SynastryAspectContact] | Contacts with classification |
house_overlay(chart_source, target_houses, ...) | SynastryHouseOverlay | chart_source planets in target_houses |
mutual_house_overlays(chart_a, houses_a, chart_b, houses_b, ...) | MutualHouseOverlay | Both overlay directions |
Composite Charts
from moira.facade import (
composite_chart, composite_chart_reference_place,
CompositeChart,
)
comp = composite_chart(chart_a, chart_b, houses_a, houses_b)
# CompositeChart(planets/nodes: dict[str, float], cusps: list[float], asc, mc)
The pure midpoint method midpoint-combines both source house frames when both
are supplied. Its computation truth reports the common requested/effective
source house system when one exists and echoes the resulting composite MC;
reference_latitude and composite_armc remain None because that method does
not construct a reference-place ARMC frame.
Davison Relationship Charts
from moira.facade import (
davison_chart, davison_chart_uncorrected,
davison_chart_reference_place, davison_chart_spherical_midpoint,
davison_chart_corrected,
DavisonChart, DavisonInfo,
)
Four variants differing in how the geographic and temporal midpoints are computed:
| Variant | Function | Midpoint time | Midpoint location |
|---|---|---|---|
| Standard | davison_chart | JD arithmetic mean | Spherical midpoint |
| Uncorrected | davison_chart_uncorrected | Arithmetic mean | Arithmetic mean |
| Reference Place | davison_chart_reference_place | Arithmetic mean | Supplied explicitly |
| Spherical | davison_chart_spherical_midpoint | Arithmetic mean | Great-circle midpoint |
| Corrected | davison_chart_corrected | Corrected for JD midpoint | Spherical midpoint |
DavisonChart: chart (Chart), info (DavisonInfo — midpoint JD, lat, lon).
13. Geography
AstroCartoGraphy
from moira.facade import acg_lines, acg_from_chart, ACGLine
| Function | Returns | Description |
|---|---|---|
acg_lines(planet_ra_dec, gmst_deg, lat_step=2.0) | list[ACGLine] | ACG lines given a pre-built RA/Dec dict and GMST |
acg_from_chart(chart, bodies=None, lat_step=2.0) | list[ACGLine] | ACG lines directly from a Chart |
acg_lines is the low-level engine. acg_from_chart is a convenience wrapper that
handles GAST extraction and calls sky_position_at for each body.
ACGLine fields
| Field | Type | Description |
|---|---|---|
planet | str | Body name |
line_type | str | "MC" / "IC" / "ASC" / "DSC" |
longitude | float | None | Geographic longitude for MC/IC meridians |
points | list[tuple[float, float]] | (lat, lon) curve points for ASC/DSC |
MC/IC lines are meridians: longitude is set, points is empty.
ASC/DSC lines are curves: points is set, longitude is None.
from moira.facade import Moira, Body
from datetime import datetime, timezone
m = Moira()
dt = datetime(1988, 4, 4, 14, 30, tzinfo=timezone.utc)
chart = m.chart(dt)
lines = m.astrocartography(chart, observer_lat=51.5, observer_lon=-0.1)
for line in lines:
if line.line_type == "MC":
print(f"{line.planet} MC meridian: {line.longitude:.2f}°E")
else:
print(f"{line.planet} {line.line_type}: {len(line.points)} points")
Local Space
from moira.facade import local_space_positions, local_space_from_chart, LocalSpacePosition
| Function | Returns | Description |
|---|---|---|
local_space_positions(planet_ra_dec, latitude, lst_deg) | list[LocalSpacePosition] | Azimuth/altitude from RA/Dec and LST |
local_space_from_chart(chart, observer_lat, observer_lon, bodies=None) | list[LocalSpacePosition] | Convenience wrapper for a Chart |
LocalSpacePosition fields
| Field | Type | Description |
|---|---|---|
body | str | Body name |
azimuth | float | Compass bearing 0-360 degrees (North = 0, East = 90) |
altitude | float | Elevation above (+) or below (-) horizon |
is_above | bool | True when altitude >= 0 |
Method: compass_direction() -> str - returns an 8-point compass label (N/NE/E/SE/S/SW/W/NW).
ls = m.local_space(chart, latitude=51.5, longitude=-0.1)
for pos in ls:
arrow = "↑" if pos.is_above else "↓"
print(f"{pos.body:10s} Az {pos.azimuth:.1f}° {pos.compass_direction():2s} "
f"Alt {pos.altitude:+.1f}° {arrow}")
Parans
Parans identify simultaneous horizon and meridian crossings shared by two stars or planets — a complementary layer to ACG.
from moira.facade import (
find_parans, find_parans_with_inventory,
natal_parans, natal_parans_with_inventory, natal_angular_contacts,
evaluate_paran_site, sample_paran_field, analyze_paran_field,
evaluate_paran_stability, extract_paran_field_contours,
consolidate_paran_contours, analyze_paran_field_structure,
Paran, ParanCrossing, ParanSignature, ParanStrength,
ParanSiteResult, ParanFieldSample, ParanFieldAnalysis,
ParanContourPathSet, ParanFieldStructure,
DEFAULT_PARAN_POLICY, PARAN_POLICY_PRESETS, ParanPolicyPreset,
PARAN_STAR_CANON, ParanStarTier, list_paran_stars,
CIRCLE_TYPES,
)
| Function | Returns | Description |
|---|---|---|
find_parans(bodies, jd_day, lat, lon, orb_minutes=4.0, policy=None) | list[Paran] | Paran crossings for a supplied body-name list at a location |
find_parans_with_inventory(...) | ParanSearchResult | Paran events plus four-circle availability for every requested body |
natal_parans(bodies, natal_jd, lat, lon, orb_minutes=4.0, policy=None) | list[Paran] | Full birth-day paran search |
natal_parans_with_inventory(...) | ParanSearchResult | Birth-day parans plus crossing availability |
natal_angular_contacts(bodies, natal_jd, lat, lon, orb_minutes=2.0) | list[NatalAngularContact] | Individual crossings near the explicit birth moment; not a two-body paran search |
evaluate_paran_site(target, jd_day, lat, lon, ...) | ParanSiteResult | Recompute one paran identity at a location |
sample_paran_field(target, jd_day, latitudes, longitudes, ...) | list[ParanFieldSample] | Grid of site results for one paran identity |
analyze_paran_field(samples, metric, threshold) | ParanFieldAnalysis | Identify active regions, peaks, and threshold crossings |
evaluate_paran_stability(paran, jd_day, lat, lon, ...) | ParanStability | Recompute one paran under time-anchor perturbations |
extract_paran_field_contours(samples, metric, threshold) | ParanContourExtraction | Extract contour segments from a rectangular sampled field |
consolidate_paran_contours(extraction) | ParanContourPathSet | Stitch contour segments into paths and report orphans |
analyze_paran_field_structure(analysis, path_set) | ParanFieldStructure | Derive path hierarchy and region/peak associations |
list_paran_stars(tiers=None, available_only=True) | tuple[ParanStarCanonEntry, ...] | Engine-owned working canon with Royal, Behenian, and Ptolemaic memberships |
REST consumers use:
GET /v1/parans/star-canonPOST /v1/parans/searchPOST /v1/parans/natalPOST /v1/parans/natal-angular-contactsPOST /v1/parans/sitePOST /v1/parans/field/{samples,analysis,contours,paths,structure}POST /v1/website/parans/packet
Search and natal requests may set include_crossing_inventory=true. All paran
request families accept policy_preset, currently permissive or
star_planet_only. The website packet composes existing engine truth; it does
not own a second paran or heliacal implementation. Star-star paran computation
is kernel-free. Optional heliacal inclusion requires planetary-kernel access
for solar ephemeris truth; an unavailable kernel is returned as an explicit
packet warning rather than an approximation.
Paran fields
| Field | Type | Description |
|---|---|---|
body1 | str | First body |
body2 | str | Second body |
circle1 | str | Circle type for the first body |
circle2 | str | Circle type for the second body |
jd1 | float | Event JD for the first body crossing |
jd2 | float | Event JD for the second body crossing |
orb_min | float | Difference between the crossings in minutes of time |
crossing1 | ParanCrossing | Crossing details for the first body |
crossing2 | ParanCrossing | Crossing details for the second body |
signature | ParanSignature | Combined paran signature metadata |
14. Fixed Stars
Unified fixed-star surface (star_registry.csv + metadata sidecars)
from moira.facade import (
star_at, all_stars_at,
list_named_stars, find_named_stars, list_stars, find_stars, star_magnitude,
load_catalog,
heliacal_rising_event, heliacal_setting_event, heliacal_rising, heliacal_setting,
heliacal_catalog_batch,
star_chart_condition_profile, star_condition_network_profile,
FixedStar, HeliacalEvent, HeliacalBatchResult,
FixedStarLookupPolicy, HeliacalSearchPolicy, FixedStarComputationPolicy,
FixedStarTruth, FixedStarClassification,
UnifiedStarRelation, UnifiedStarMergePolicy, UnifiedStarComputationPolicy,
StarConditionState, StarConditionProfile,
StarChartConditionProfile, StarConditionNetworkProfile,
)
| Function | Returns | Description |
|---|---|---|
star_at(name, jd_tt, policy=None) | FixedStar | Public fixed-star lookup, with sovereign registry data and Gaia-derived enrichment fields when available |
all_stars_at(jd_tt) | dict[str, FixedStar] | All named stars at one epoch |
list_named_stars() / list_stars() | list[str] | All named stars in the sovereign registry |
find_named_stars(query) / find_stars(query) | list[str] | Fuzzy search across named stars and nomenclature aliases |
star_magnitude(name) | float | Visual magnitude |
load_catalog() | None | Reload the sovereign fixed-star registry and indexes |
heliacal_rising(name, jd_ut, latitude, longitude) | float | None | JD of heliacal rising |
heliacal_setting(name, jd_ut, latitude, longitude) | float | None | JD of heliacal setting |
heliacal_rising_event(name, jd_ut, lat, lon) | HeliacalEvent | Heliacal rising with classification |
heliacal_setting_event(name, jd_ut, lat, lon) | HeliacalEvent | Heliacal setting with classification |
heliacal_catalog_batch(event_kind, jd_start, latitude, longitude, *, max_magnitude=6.5, names=None, search_days=400, policy=None) | HeliacalBatchResult | Batch heliacal search across the fixed-star registry |
There is no separate public fixed_star_at function in 1.0.3. The public
lookup surface is star_at(...), which returns a FixedStar vessel.
Specialty module helper: from moira.stars import star_light_time_split
returns (observed, true) fixed-star positions separated by stellar light-time,
but it is not re-exported by moira.facade in 1.0.3.
Catalog convenience sets
royal_stars.py and behenian_stars.py are standalone sub-modules — not re-exported at the moira top-level. Import them directly:
from moira.royal_stars import (
list_royal_stars, available_royal_stars, royal_star_at,
ALDEBARAN, REGULUS, ANTARES, FOMALHAUT,
)
from moira.behenian_stars import (
list_behenian_stars, available_behenian_stars, behenian_star_at,
ALGOL, ALCYONE, SIRIUS, SPICA, ARCTURUS, ALPHECCA, VEGA, # + 8 more constants
)
Search helpers and merged fields
| Function | Returns | Description |
|---|---|---|
star_at(name, jd_tt) | FixedStar | Named star with Gaia enrichment when available |
stars_near(longitude, orb, jd_tt) | list[FixedStar] | Stars within orb° of a longitude |
stars_by_magnitude(max_mag, jd_tt) | list[FixedStar] | Stars brighter than max_mag |
list_named_stars() | list[str] | All traditionally-named stars |
find_named_stars(query) | list[str] | Fuzzy name search across named stars |
FixedStar fields
| Field | Type | Description |
|---|---|---|
name | str | Traditional name |
nomenclature | str | None | Catalog designation or alternate nomenclature |
longitude | float | Ecliptic longitude (°) |
latitude | float | Ecliptic latitude (°) |
magnitude | float | Visual magnitude |
bp_rp | float | None | Gaia BP−RP colour index |
teff_k | float | None | Effective temperature (K) from Gaia |
parallax_mas | float | None | Gaia parallax (mas) |
distance_ly | float | None | Distance in light-years |
quality | StellarQuality | None | Stellar classification from Gaia colours |
source | str | Data source used for the merged record |
is_topocentric | bool | Whether topocentric correction was applied |
computation_truth | FixedStarTruth | Computation truth data |
classification | FixedStarClassification | Classification metadata |
relation | UnifiedStarRelation | Relation metadata |
condition_profile | StarConditionProfile | Consolidated star condition profile |
Gaia enrichment status
FixedStar records may expose Gaia-derived fields such as bp_rp,
parallax_mas, distance_ly, and quality, but Moira 1.0.3 does not export a
standalone public Gaia loader/query surface. Gaia enrichment is internal to the
merged fixed-star API rather than a separate public subsystem.
General visibility engine
Moira also exposes a generalized observational visibility layer that is broader than the fixed-star heliacal helpers. This is the public surface used for criterion-based visibility judgments and event searches.
from moira.facade import (
HeliacalEventKind, VisibilityTargetKind,
LightPollutionClass, LightPollutionDerivationMode,
ObserverAid, ObserverVisibilityEnvironment,
VisibilityCriterionFamily, VisibilityExtinctionModel, VisibilityTwilightModel,
ExtinctionCoefficient, MoonlightPolicy,
VisibilityPolicy, VisibilitySearchPolicy,
LunarCrescentVisibilityClass, LunarCrescentDetails,
VisibilityAssessment, GeneralVisibilityEvent,
visibility_assessment, visual_limiting_magnitude, visibility_event,
)
| Function | Returns | Description |
|---|---|---|
visibility_assessment(body, jd_ut, lat, lon, *, policy=None) | VisibilityAssessment | Criterion-based visibility judgment at one observing moment |
visual_limiting_magnitude(jd_ut, lat, lon, *, policy=None) | float | Estimated naked-eye limiting magnitude at the site and time |
visibility_event(body, event_kind, jd_start, lat, lon, *, heliacal_policy=None, visibility_policy=None, search_policy=None) | GeneralVisibilityEvent | None | Search for the next generalized visibility event matching the requested kind |
Key policy and vessel types: VisibilityPolicy, VisibilitySearchPolicy,
VisibilityAssessment, GeneralVisibilityEvent, ObserverVisibilityEnvironment,
LunarCrescentDetails.
Variable Stars
from moira.facade import (
variable_star, list_variable_stars, variable_stars_by_type,
phase_at, magnitude_at, next_minimum, next_maximum,
minima_in_range, maxima_in_range,
malefic_intensity, benefic_strength, is_in_eclipse,
algol_phase, algol_magnitude, algol_next_minimum, algol_is_eclipsed,
star_phase_state, star_condition_profile, catalog_profile, star_state_pair,
validate_variable_star_catalog,
VariableStar, VarType, VarStarPolicy, DEFAULT_VAR_STAR_POLICY,
StarPhaseState, StarConditionProfile, CatalogProfile, StarStatePair,
)
VarType — variable star classification
| Constant | Meaning |
|---|---|
VarType.ECLIPSING_ALGOL | Algol-type (EA) — sharp minima |
VarType.ECLIPSING_BETA | Beta Lyrae-type (EB) — continuous variation |
VarType.ECLIPSING_W_UMA | W Ursae Maj.-type (EW) — contact binaries |
VarType.CEPHEID | Delta Cephei-type pulsating |
VarType.RR_LYRAE | RR Lyrae pulsating |
VarType.MIRA | Mira-type long-period |
VarType.SEMI_REG_SG | Semi-regular supergiant |
VarType.SEMI_REG | Semi-regular |
VariableStar fields
| Field | Type | Description |
|---|---|---|
name | str | Star name |
designation | str | None | Catalog designation |
var_type | VarType | Variability classification |
period_days | float | Period in days (0 if irregular) |
epoch_jd | float | Reference epoch JD |
epoch_is_minimum | bool | True when the epoch is a minimum, False when it is a maximum |
mag_max | float | Magnitude at maximum brightness |
mag_min | float | Magnitude at minimum brightness |
mag_min2 | float | None | Secondary minimum magnitude when applicable |
eclipse_width | float | Eclipse duration as fraction of period (EA only) |
classical_quality | str | "malefic" / "benefic" / "neutral" / "mixed" |
note | str | Short catalog note |
Derived properties: amplitude, is_eclipsing, is_pulsating, is_long_period,
is_irregular, is_malefic, is_benefic, type_class.
Core functions
| Function | Returns | Description |
|---|---|---|
variable_star(name) | VariableStar | Look up a star by name |
list_variable_stars() | list[str] | All catalog star names (20 stars) |
variable_stars_by_type(var_type) | list[VariableStar] | Filter catalog by type |
phase_at(star, jd) | float | Phase in [0, 1) at a given JD |
magnitude_at(star, jd) | float | Interpolated visual magnitude |
malefic_intensity(star, jd, policy=None) | float | Malefic score [0, 1] |
benefic_strength(star, jd, policy=None) | float | Benefic score [0, 1] |
is_in_eclipse(star, jd, policy=None) | bool | True when near minimum for eclipsing type |
next_minimum(star, jd) | float | JD of next minimum |
next_maximum(star, jd) | float | JD of next maximum |
minima_in_range(star, jd_start, jd_end) | list[float] | All minima in range |
maxima_in_range(star, jd_start, jd_end) | list[float] | All maxima in range |
Algol convenience functions
| Function | Returns | Description |
|---|---|---|
algol_phase(jd) | float | Algol phase at JD |
algol_magnitude(jd) | float | Algol magnitude at JD |
algol_next_minimum(jd) | float | JD of next Algol minimum |
algol_is_eclipsed(jd, policy=None) | bool | True when Algol is near minimum |
Condition profile API
state = star_phase_state(star, jd)
# StarPhaseState(star, jd, phase, magnitude, malefic_score, benefic_score, in_eclipse)
profile = star_condition_profile(star, jd)
# StarConditionProfile — catalog truth + dynamic state in one record
cat = catalog_profile(jd)
# CatalogProfile — aggregate over all 20 catalog stars
pair = star_state_pair(star_a, star_b, jd)
# StarStatePair(primary, secondary) with structural relationship properties
Multiple Star Systems
from moira.facade import (
multiple_star, list_multiple_stars, multiple_stars_by_type,
angular_separation_at, position_angle_at,
is_resolvable, dominant_component, combined_magnitude, components_at,
sirius_ab_separation_at, sirius_b_resolvable,
castor_separation_at, alpha_cen_separation_at,
MultipleStarSystem, StarComponent, OrbitalElements, MultiType,
)
| Function | Returns | Description |
|---|---|---|
multiple_star(name) | MultipleStarSystem | Retrieve a multiple-star system by name |
list_multiple_stars() | list[str] | All catalog system names |
multiple_stars_by_type(multi_type) | list[MultipleStarSystem] | Filter by system type |
angular_separation_at(system, jd_tt) | float | Current angular separation (arcsec) |
position_angle_at(system, jd_tt) | float | Current position angle (°) |
is_resolvable(system, jd_tt, aperture_mm) | bool | True if resolvable with aperture |
dominant_component(system) | StarComponent | Brighter/primary component |
combined_magnitude(system) | float | Combined visual magnitude |
components_at(system, jd_tt) | dict | Full component/separation snapshot for the system |
sirius_ab_separation_at(jd_tt) | float | Sirius A–B separation (arcsec) |
sirius_b_resolvable(jd_tt, aperture_mm=200) | bool | True if Sirius B is resolvable |
castor_separation_at(jd_tt) | float | Castor AB separation (arcsec) |
alpha_cen_separation_at(jd_tt) | float | α Cen A–B separation (arcsec) |
MultiType constants: VISUAL WIDE SPECTROSCOPIC OPTICAL
15. Eclipses & Phenomena
Solar & Lunar Eclipses
from moira.facade import (
EclipseData, EclipseEvent, EclipseType, EclipseCalculator,
SolarBodyCircumstances, SolarEclipseLocalCircumstances,
LocalContactCircumstances, LunarEclipseAnalysis, LunarEclipseLocalCircumstances,
)
calc = EclipseCalculator(reader=get_reader())
data = calc.calculate(dt) # EclipseData
EclipseData fields
| Field | Type | Description |
|---|---|---|
sun_longitude | float | Sun longitude at the evaluated moment |
moon_longitude | float | Moon longitude at the evaluated moment |
node_longitude | float | Node longitude at the evaluated moment |
moon_latitude | float | Moon latitude relative to the ecliptic |
eclipse_type | EclipseType | TOTAL_SOLAR / ANNULAR / PARTIAL_SOLAR / PENUMBRAL / PARTIAL_LUNAR / TOTAL_LUNAR |
is_eclipse_season | bool | Whether the Sun is close enough to the nodes for eclipse season |
is_solar_eclipse | bool | Solar eclipse flag |
is_lunar_eclipse | bool | Lunar eclipse flag |
eclipse_magnitude | float | Computed eclipse magnitude |
saros_index | float | Saros cycle position/index |
metonic_year | float | Metonic cycle position |
moon_distance_km | float | Geocentric Moon distance in kilometers |
galactic_center_longitude | float | Galactic center longitude reference |
sun_apparent_radius | float | Apparent solar radius |
moon_apparent_radius | float | Apparent lunar radius |
earth_shadow_apparent_radius | float | Apparent umbral radius |
earth_penumbra_apparent_radius | float | Apparent penumbral radius |
sun_stone | int | Aubrey-stone style solar index |
moon_stone | int | Aubrey-stone style lunar index |
node_stone | int | Aubrey-stone style node index |
south_node_stone | int | Aubrey-stone style south-node index |
angular_separation_3d | float | 3D Sun/Moon angular separation |
solar_topocentric_separation | float | Topocentric Sun/Moon separation |
sun_node_distance | float | Distance from Sun to node |
metonic_is_reset | bool | Whether the Metonic cycle resets here |
moon_parallax | float | Lunar parallax |
sun_side | int | Stonehenge side index for the Sun |
sun_pos_in_side | int | Position of the Sun within the side index |
NASA-compatible lunar eclipse API
from moira.facade import (
NasaLunarEclipseContacts, NasaLunarEclipseEvent,
next_nasa_lunar_eclipse, previous_nasa_lunar_eclipse,
translate_lunar_eclipse_event,
)
event = next_nasa_lunar_eclipse(jd_start, reader=reader)
prev = previous_nasa_lunar_eclipse(jd_start, reader=reader)
The default compatibility method is
nasa_shadow_axis_apparent_sun_moon. It evaluates the Sun and Moon from the
same reception-epoch Earth state, applies reception light-time and then annual
aberration to both directions, and omits gravitational deflection, topocentric
parallax, and atmospheric refraction. NasaLunarEclipseEvent.canon_method and
.source_model identify this policy. The legacy geometric and retarded method
identifiers remain explicitly selectable on the lower-level canon functions;
they are not ambient fallbacks.
This method is validated as a DE441/LE441 compatibility computation against NASA/GSFC products that declare VSOP87/ELP2000-85. It does not claim exact ephemeris parity. Existing function signatures and result-vessel fields are unchanged, while the compatibility method label and numerical results intentionally reflect the repaired apparent reduction.
Planetary Phenomena
from moira.facade import (
greatest_elongation, perihelion, aphelion,
next_moon_phase, moon_phases_in_range,
PhenomenonEvent,
)
| Function | Returns | Description |
|---|---|---|
greatest_elongation(body, jd_start, direction="east", reader=None, max_days=600.0) | PhenomenonEvent | None | Next greatest elongation of Mercury or Venus in the requested direction |
perihelion(body, jd_start, reader=None, max_days=None) | PhenomenonEvent | None | Next perihelion passage |
aphelion(body, jd_start, reader=None, max_days=None) | PhenomenonEvent | None | Next aphelion passage |
next_moon_phase(phase_name, jd_start, reader=None) | PhenomenonEvent | Next exact named moon phase ("New Moon", "First Quarter", "Full Moon", etc.) |
moon_phases_in_range(jd_start, jd_end, reader=None) | list[PhenomenonEvent] | All eight standard moon phases in a date range |
PhenomenonEvent: body, phenomenon, jd_ut, value.
Occultations
from moira.facade import (
close_approaches, lunar_occultation, lunar_star_occultation, all_lunar_occultations,
lunar_occultation_path_topology, lunar_occultation_path_topology_at,
lunar_star_occultation_path_topology, lunar_star_occultation_path_topology_at,
CloseApproach, LunarOccultation, OccultationPathTopology,
)
| Function | Returns | Description |
|---|---|---|
close_approaches(body_a, body_b, jd_start, jd_end, max_sep_deg=1.0, step_days=0.5, reader=None) | list[CloseApproach] | Close conjunctions within the requested separation threshold |
lunar_occultation(body, jd_start, jd_end, reader=None) | list[LunarOccultation] | Moon occultation events for a planet |
lunar_star_occultation(star_lon, star_lat, star_name, jd_start, jd_end, step_days=0.25, observer_lat=None, observer_lon=None, observer_elev_m=0.0, reader=None) | list[LunarOccultation] | Moon occultation of a fixed star at a supplied ecliptic position |
all_lunar_occultations(jd_start, jd_end, planets=None, reader=None) | list[LunarOccultation] | Lunar occultations for the default planet set or a supplied planet list |
lunar_occultation_path_topology(target, jd_start, jd_end, step_days=0.25, sample_count=65, observer_elev_m=0.0, reader=None) | list[OccultationPathTopology] | Detailed nominal mean-limb planetary bands with intrinsic left/right limits and exact-pole contacts |
lunar_occultation_path_topology_at(target, jd_mid, *, sample_count=65, observer_elev_m=0.0, reader=None) | OccultationPathTopology | Detailed nominal mean-limb planetary topology at one greatest epoch |
lunar_star_occultation_path_topology(star_lon, star_lat, star_name, jd_start, jd_end, step_days=0.25, sample_count=65, observer_elev_m=0.0, reader=None) | list[OccultationPathTopology] | Detailed nominal mean-limb fixed-star bands with polar-safe topology |
lunar_star_occultation_path_topology_at(star_lon, star_lat, star_name, jd_mid, *, sample_count=65, observer_elev_m=0.0, reader=None) | OccultationPathTopology | Detailed nominal mean-limb fixed-star topology at one greatest epoch |
OccultationPathTopology.observer_elevation_m preserves the requested
observer elevation used by every center and boundary solve. Its intrinsic
left and right identities follow increasing UT1 along the center track and
are not geographic north/south labels. This detailed two-sided product admits
only lunar_limb_model="SPHERICAL_MEAN_LIMB"; profile-conditioned graze
products remain separate.
The two range searches admit at most 400 days, 0 < step_days <= 0.25, and
4096 coarse cells; step_days is a maximum cell width. Their fixed internal
contact search is independent of the output sample_count. Planetary topology
accepts Mercury through Pluto except Earth and excludes the Sun; use the solar
eclipse surfaces for Sun/Moon occultation geometry. The summary duration is
the local duration at the fixed greatest site, not global footprint lifetime.
Range results require an unconstrained greatest instant inside the requested
interval by more than max(4e-8 d, 8 binary64 ULP) at each boundary.
Optimizer witnesses coalesce only through overlapping open
positive-clearance support; tangent-only contact remains separate. Each
connected component's strongest time-local maximum is resolved on a private
at-most-30-minute lattice with a 128-cell fail-closed budget before the range
gate is reapplied. Fixed-star
labels are canonical nonblank labels without surrounding whitespace or Solar
System body identities. Observer elevation must be at least
-6378.137 * (1 - 1/298.257223563) * 1000 m, the negative WGS 84 semi-minor
axis. That is a computational-envelope floor, not an observing-site claim.
At positive heights large enough that the observer sphere reaches a body,
candidate admission switches from asin(R/d) to the conservative 180 degree direction-reversal bound; no arbitrary upper-height policy is hidden.
Sothic Cycle (Egyptian calendar)
from moira.facade import (
sothic_rising, sothic_epochs, sothic_drift_rate,
egyptian_civil_date, days_from_1_thoth, predicted_sothic_epoch_year,
sothic_chart_condition_profile, sothic_condition_network_profile,
EgyptianDate, SothicEntry, SothicEpoch,
EGYPTIAN_MONTHS, EGYPTIAN_SEASONS, EPAGOMENAL_BIRTHS,
HISTORICAL_SOTHIC_EPOCHS,
SothicComputationPolicy,
)
| Function | Returns | Description |
|---|---|---|
sothic_rising(latitude, longitude, year_start, year_end, epoch_jd=1772027.5, arcus_visionis=10.0, policy=None) | list[SothicEntry] | Sirius heliacal rising entries across a year range |
sothic_epochs(latitude, longitude, year_start, year_end, epoch_jd=1772027.5, tolerance_days=1.0, arcus_visionis=10.0, policy=None) | list[SothicEpoch] | New Year coincidences across a year range |
sothic_drift_rate(entries) | float | Drift rate derived from a list[SothicEntry] |
egyptian_civil_date(jd, epoch_jd=1772027.5, policy=None) | EgyptianDate | Wandering civil calendar date |
days_from_1_thoth(jd, epoch_jd=1772027.5) | float | Days elapsed since the last 1 Thoth |
predicted_sothic_epoch_year(known_epoch_year, n_cycles, cycle_length_years=1460.0, policy=None) | float | Predicted year after one or more Sothic cycles |
HISTORICAL_SOTHIC_EPOCHS: list of known historical epoch dates.
EPAGOMENAL_BIRTHS: five epagomenal days and their mythological births.
16. Harmograms — Spectral Harmonic Analysis
from moira.harmograms import (
# Core computation
harmonic_vector, point_set_harmonic_vector,
zero_aries_parts_harmonic_vector, parts_from_zero_aries,
intensity_function_spectrum, project_harmogram_strength,
harmogram_trace,
# Vessels
HarmonicDomain,
HarmonicVectorComponent, PointSetHarmonicVector,
ZeroAriesPart, ZeroAriesPartsSet, ZeroAriesPartsHarmonicVector,
IntensitySpectrumComponent, IntensityFunctionSpectrum,
HarmogramProjectionTerm, HarmogramProjection, HarmogramDominantTerm,
HarmogramTraceSample, HarmogramTraceSeries, HarmogramTrace,
IntensitySpectrumComparisonTerm, IntensitySpectrumComparison,
HarmogramTraceSeriesComparisonSample, HarmogramTraceSeriesComparison,
# Policies
HarmogramPolicy, HarmogramIntensityPolicy, HarmogramSamplingPolicy,
PointSetHarmonicVectorPolicy, ZeroAriesPartsPolicy,
# Enums
HarmonicVectorNormalizationMode, ZeroAriesPairConstructionMode, SelfPairMode,
HarmogramIntensityFamily, HarmogramOrbMode, GaussianWidthParameterMode,
HarmogramOrbScalingMode, HarmogramSymmetryMode,
IntensityNormalizationMode, IntensitySpectrumRealizationMode,
HarmogramProjectionRealizationMode, HarmogramSamplingMode,
HarmogramOutputMode, HarmogramChartDomain, HarmogramTraceFamily,
# Research tools
dominant_harmonic_contributors, compare_intensity_spectra, compare_trace_series,
)
The Harmograms engine is a research-facing spectral harmonic analysis subsystem. It is deliberately distinct from moira.harmonics (which computes classical harmonic chart positions for individual bodies). This package deals with harmonic spectra — the Fourier-style decomposition of an entire point set's angular distribution, not single-body positions.
This module does not generate astrological positions. It analyzes collections of longitudes (already computed by the position engines) for their harmonic structure.
The central concepts:
- Harmonic vector — the resultant vector of a point set projected onto the unit circle at harmonic H. Amplitude near 1.0 means the points cluster at H-fold symmetry; near 0.0 means they are uniformly distributed.
- Zero-Aries parts — pairwise angular differences between all bodies, projected to [0°, 360°). These are the raw material for the harmogram spectrum.
- Intensity function spectrum — the spectral distribution of harmonic energy across a defined harmonic domain.
- Harmogram trace — a time-domain trace of harmonic strength as the sky moves.
- Harmogram projection — decomposes a total strength value back onto per-harmonic contributions.
HarmonicDomain — harmonic range specifier
domain = HarmonicDomain(harmonic_start=1, harmonic_stop=12)
# .harmonics → tuple of all integers in [start, stop]
| Field | Type | Default | Description |
|---|---|---|---|
harmonic_start | int | 1 | First harmonic (must be ≥ 1) |
harmonic_stop | int | 12 | Last harmonic (must be ≥ start) |
Property: harmonics → tuple[int, ...] of all harmonics in the range.
Core Data Vessels
HarmonicVectorComponent — single harmonic result
| Field | Type | Description |
|---|---|---|
harmonic | int | Harmonic number (≥ 1) |
amplitude | float | Resultant amplitude (≥ 0); 1.0 = perfect clustering at this harmonic |
phase_deg | float | Phase of the resultant vector (°), [0°, 360°) |
Property: amplitude_squared.
PointSetHarmonicVector — harmonic vector for a named point set
| Field | Type | Description |
|---|---|---|
policy | PointSetHarmonicVectorPolicy | Normalization and domain policy used |
body_names | tuple[str, ...] | Names of the contributing points |
point_count | int | Number of points |
harmonic_zero_amplitude | float | H=0 amplitude (reflects normalization) |
components | tuple[HarmonicVectorComponent, ...] | One component per harmonic in the domain |
Method: get_component(harmonic) → HarmonicVectorComponent.
ZeroAriesPart — one pairwise angular difference
| Field | Type | Description |
|---|---|---|
source_name | str | Source body |
target_name | str | Target body |
longitude_deg | float | Angular difference projected to [0°, 360°) |
ZeroAriesPartsSet — collection of pairwise parts
| Field | Type | Description |
|---|---|---|
policy | ZeroAriesPartsPolicy | Construction policy |
source_body_names | tuple[str, ...] | Source body names |
target_body_names | tuple[str, ...] | Target body names |
parts | tuple[ZeroAriesPart, ...] | All constructed parts |
Properties: source_point_count, target_point_count, parts_count.
ZeroAriesPartsHarmonicVector — harmonic vector for a parts set
| Field | Type | Description |
|---|---|---|
vector_policy | PointSetHarmonicVectorPolicy | Normalization policy |
parts_policy | ZeroAriesPartsPolicy | Parts construction policy |
source_body_names | tuple[str, ...] | Source bodies |
target_body_names | tuple[str, ...] | Target bodies |
parts_count | int | Number of parts contributing |
harmonic_zero_amplitude | float | H=0 amplitude |
components | tuple[HarmonicVectorComponent, ...] | Per-harmonic components |
Method: get_component(harmonic) → HarmonicVectorComponent.
Intensity Function Spectrum
The intensity function spectrum evaluates how strongly the point set concentrates at each harmonic. Unlike the harmonic vector (which uses raw resultants), the intensity function applies a bell-shaped orb around each aspect, making it sensitive to near-aspect clustering.
spectrum = intensity_function_spectrum(longitudes, harmonic, policy=...)
# IntensityFunctionSpectrum
IntensitySpectrumComponent fields
| Field | Type | Description |
|---|---|---|
harmonic | int | Harmonic number |
amplitude | float | Intensity amplitude at this harmonic (≥ 0) |
phase_deg | float | Phase (°), [0°, 360°) |
IntensityFunctionSpectrum fields
| Field | Type | Description |
|---|---|---|
policy | HarmogramIntensityPolicy | Intensity policy used |
harmonic_number | int | The primary harmonic being analyzed |
realization_mode | IntensitySpectrumRealizationMode | Computation method |
harmonic_zero_amplitude | float | H=0 reference amplitude |
components | tuple[IntensitySpectrumComponent, ...] | Per-harmonic components |
Method: get_component(harmonic) → IntensitySpectrumComponent.
Harmogram Projection
Projects a harmogram strength back onto per-harmonic contributions, showing which harmonics drive the total score.
proj = project_harmogram_strength(source_vector, intensity_spectrum, policy=...)
# HarmogramProjection
HarmogramProjectionTerm fields (one per harmonic)
| Field | Type | Description |
|---|---|---|
harmonic | int | Harmonic number |
source_amplitude | float | Source vector amplitude at this harmonic |
source_phase_deg | float | Source vector phase at this harmonic |
intensity_amplitude | float | Intensity spectrum amplitude at this harmonic |
intensity_phase_deg | float | Intensity spectrum phase at this harmonic |
signed_contribution | float | Signed contribution to total strength (positive = reinforcing) |
HarmogramProjection fields
| Field | Type | Description |
|---|---|---|
source_vector | PointSetHarmonicVector | ZeroAriesPartsHarmonicVector | Source point set |
intensity_spectrum | IntensityFunctionSpectrum | Intensity spectrum used |
normalization_mode | HarmonicVectorNormalizationMode | Normalization applied |
realization_mode | HarmogramProjectionRealizationMode | Computation method |
harmonic_zero_contribution | float | H=0 contribution |
total_strength | float | Total projected strength (sum of all term contributions) |
terms | tuple[HarmogramProjectionTerm, ...] | One term per harmonic |
Method: get_term(harmonic) → HarmogramProjectionTerm.
Harmogram Trace
A time-domain trace of projected harmonic strength across a sequence of sky epochs.
samples = [
{
"time": 2451545.0,
"positions": [
{"name": "Sun", "degree": 280.0},
{"name": "Moon", "degree": 223.0},
],
},
{
"time": 2451546.0,
"positions": [
{"name": "Sun", "degree": 281.0},
{"name": "Moon", "degree": 236.0},
],
},
]
trace = harmogram_trace(samples, harmonic_numbers=(1, 2, 3, 4, 5))
# HarmogramTrace; each trace.series item exposes .harmonic_number and .strengths
HarmogramTraceSample fields (one per epoch)
| Field | Type | Description |
|---|---|---|
sample_index | int | Index into the epoch sequence (≥ 0) |
sample_time | float | JD of this sample |
source_vector | ZeroAriesPartsHarmonicVector | Parts vector for this epoch |
projection | HarmogramProjection | Full projection at this epoch |
total_strength | float | Total projected strength at this epoch |
HarmogramTraceSeries fields
| Field | Type | Description |
|---|---|---|
harmonic_number | int | The harmonic being traced |
intensity_spectrum | IntensityFunctionSpectrum | Shared intensity spectrum |
samples | tuple[HarmogramTraceSample, ...] | All samples in epoch order |
Property: strengths → tuple[float, ...] of total_strength per sample.
HarmogramTrace fields
| Field | Type | Description |
|---|---|---|
policy | HarmogramPolicy | Governing policy |
interval_start | float | JD start of the trace interval |
interval_stop | float | JD end of the trace interval |
sample_times | tuple[float, ...] | All epoch JDs in order |
series | tuple[HarmogramTraceSeries, ...] | One series per harmonic in the output |
Research Tools
dominant = dominant_harmonic_contributors(projection, top_n=5)
# list[HarmogramDominantTerm] — harmonics ranked by |signed_contribution|
HarmogramDominantTerm fields
| Field | Type | Description |
|---|---|---|
harmonic | int | Harmonic number |
absolute_contribution | float | Absolute value of the contribution (≥ 0) |
signed_contribution | float | Signed contribution (positive = reinforcing) |
cmp = compare_intensity_spectra(spectrum_a, spectrum_b)
# IntensitySpectrumComparison
IntensitySpectrumComparison fields
| Field | Type | Description |
|---|---|---|
left | IntensityFunctionSpectrum | First spectrum |
right | IntensityFunctionSpectrum | Second spectrum |
max_absolute_delta | float | Maximum per-harmonic amplitude difference |
terms | tuple[IntensitySpectrumComparisonTerm, ...] | Per-harmonic delta terms |
IntensitySpectrumComparisonTerm: harmonic, left_amplitude, right_amplitude, amplitude_delta.
trace_cmp = compare_trace_series(series_a, series_b)
# HarmogramTraceSeriesComparison
HarmogramTraceSeriesComparison: left, right, max_absolute_delta, samples (each: sample_index, sample_time, left_strength, right_strength, delta).
Policy Objects
HarmogramPolicy — master policy
| Field | Type | Default | Description |
|---|---|---|---|
point_set_policy | PointSetHarmonicVectorPolicy | default | Normalization and domain for point sets |
parts_policy | ZeroAriesPartsPolicy | default | Zero-Aries parts construction |
intensity_policy | HarmogramIntensityPolicy | default | Intensity function shape |
sampling_policy | HarmogramSamplingPolicy | default | Trace sampling |
output_mode | HarmogramOutputMode | MULTI_HARMONIC_FAMILY | Single vs multi-harmonic output |
chart_domain | HarmogramChartDomain | DYNAMIC_SKY_ONLY_TRACE | What the trace represents |
trace_family | HarmogramTraceFamily | DYNAMIC_ZERO_ARIES_PARTS | Parts construction family |
chart_domain and trace_family must be consistent (enforced by __post_init__).
HarmogramIntensityPolicy — intensity function shape
| Field | Type | Default | Description |
|---|---|---|---|
family | HarmogramIntensityFamily | COSINE_BELL_HARMONIC_ASPECTS | Aspect weighting shape |
include_conjunction | bool | True | Whether to include H-fold conjunctions |
orb_mode | HarmogramOrbMode | COSINE_BELL | Orb weighting function (must match family) |
orb_scaling_mode | HarmogramOrbScalingMode | EQUATED_TO_HARMONIC_ONE | How orb scales with harmonic |
symmetry_mode | HarmogramSymmetryMode | STAR_SYMMETRIC | Star-symmetric or conjunction-excluded |
normalization_mode | IntensityNormalizationMode | PEAK_ONE | Spectrum normalization |
harmonic_domain | HarmonicDomain | H1–H12 | Harmonics evaluated |
orb_width_deg | float | 24.0 | Orb width at H=1 (°) |
gaussian_width_parameter_mode | GaussianWidthParameterMode | FWHM | Gaussian width interpretation |
gaussian_width_deg | float | None | None | Gaussian width (required for Gaussian family) |
sample_count | int | 4096 | Quadrature sample count (≥ 256) |
HarmogramIntensityFamily values: COSINE_BELL_HARMONIC_ASPECTS TOP_HAT_HARMONIC_ASPECTS TRIANGULAR_HARMONIC_ASPECTS GAUSSIAN_HARMONIC_ASPECTS
HarmogramOrbMode must match the family: COSINE_BELL TOP_HAT TRIANGULAR GAUSSIAN
HarmogramSymmetryMode values: STAR_SYMMETRIC (includes conjunction) CONJUNCTION_EXCLUDED
PointSetHarmonicVectorPolicy
| Field | Type | Default | Description |
|---|---|---|---|
normalization_mode | HarmonicVectorNormalizationMode | MEAN_RESULTANT | RAW_SUM or MEAN_RESULTANT |
harmonic_domain | HarmonicDomain | H1–H12 | Harmonics computed |
ZeroAriesPartsPolicy
| Field | Type | Default | Description |
|---|---|---|---|
pair_construction_mode | ZeroAriesPairConstructionMode | ORDERED | ORDERED (A→B ≠ B→A) or UNORDERED |
self_pair_mode | SelfPairMode | INCLUDE | Whether to include self-pairs (A→A = 0°) |
HarmogramChartDomain and HarmogramTraceFamily constraints
chart_domain | Compatible trace_family |
|---|---|
DYNAMIC_SKY_ONLY_TRACE | DYNAMIC_ZERO_ARIES_PARTS |
TRANSIT_TO_NATAL_TRACE | TRANSIT_TO_NATAL_ZERO_ARIES_PARTS |
DIRECTED_OR_PROGRESSED_TRACE | DIRECTED_TO_NATAL_ZERO_ARIES_PARTS or PROGRESSED_TO_NATAL_ZERO_ARIES_PARTS |
Example: natal chart H4 spectral analysis
from moira.harmograms import (
parts_from_zero_aries, zero_aries_parts_harmonic_vector,
intensity_function_spectrum, project_harmogram_strength,
dominant_harmonic_contributors,
HarmonicDomain, HarmogramIntensityPolicy, PointSetHarmonicVectorPolicy,
)
from moira.facade import Moira
from datetime import datetime, timezone
m = Moira()
chart = m.chart(datetime(1988, 4, 4, 14, 30, tzinfo=timezone.utc))
lons = chart.longitudes(include_nodes=False) # dict[str, float]
domain = HarmonicDomain(harmonic_start=1, harmonic_stop=16)
# Build Zero-Aries parts from the natal chart
parts = parts_from_zero_aries(lons)
# Harmonic vector for H4
vec_policy = PointSetHarmonicVectorPolicy(harmonic_domain=domain)
hvec = zero_aries_parts_harmonic_vector(parts, 4, policy=vec_policy)
print(f"H4 amplitude: {hvec.get_component(4).amplitude:.4f}")
# Intensity spectrum at H4
int_policy = HarmogramIntensityPolicy(harmonic_domain=domain, orb_width_deg=18.0)
spectrum = intensity_function_spectrum(lons, 4, policy=int_policy)
# Project — which harmonics contribute most?
proj = project_harmogram_strength(hvec, spectrum)
print(f"Total strength: {proj.total_strength:.4f}")
dominant = dominant_harmonic_contributors(proj, top_n=4)
for term in dominant:
print(f" H{term.harmonic}: {term.signed_contribution:+.4f}")
17. Constellation Oracle
# Import directly from the sub-module for the constellation you need:
from moira.constellations.stars_orion import (
RIGEL, BETELGEUSE, BELLATRIX, ALNILAM, ALNITAK, MINTAKA, SAIPH,
stars_in_orion, orion_star_at,
rigel_at, betelgeuse_at, bellatrix_at, # etc.
)
The Constellation Oracle groups the fixed-star catalog by IAU constellation. Each of the 48 sub-modules provides:
- Named string constants for each catalogued star (e.g.
RIGEL = "Rigel") - A constellation-scoped dispatcher (
orion_star_at(name, jd_tt)) that validates names against the constellation and callsmoira.stars.star_at - Per-star convenience functions (
rigel_at(jd_tt),betelgeuse_at(jd_tt)) - List helpers (
stars_in_orion(),available_in_orion())
No symbols are re-exported from moira.constellations.__init__; always import from the specific sub-module.
Module naming convention
Sub-modules follow the pattern moira.constellations.stars_<constellation>, where <constellation> is the IAU abbreviation in lowercase:
stars_andromeda stars_aquarius stars_aquila stars_aries
stars_bootes stars_cancer stars_canis_major stars_canis_minor
stars_capricorn stars_carina stars_cassiopeia stars_centaurus
stars_corvus stars_crater stars_crux stars_cygnus
stars_draco stars_gemini stars_hercules stars_hydra
stars_leo stars_libra stars_lyra stars_ophiuchus
stars_orion stars_pegasus stars_perseus stars_pisces
stars_sagittarius stars_scorpius stars_taurus stars_ursa_major
stars_ursa_minor stars_virgo ... (48 total)
Per-module interface pattern
Every constellation module exposes the same interface pattern:
from moira.constellations.stars_scorpius import (
ANTARES, SHAULA, LESATH, DSCHUBBA, GRAFFIAS,
# ... other star name constants
stars_in_scorpius, # list[str] — all catalogued star names
available_in_scorpius, # list[str] — names resolvable right now
scorpius_star_at, # (name, jd_tt) → FixedStar
antares_at, # (jd_tt) → FixedStar
shaula_at,
# ... one function per catalogued star
)
Usage
from moira.facade import jd_from_datetime, utc_to_tt
from moira.constellations.stars_taurus import (
ALDEBARAN, ALCYONE, PLEIADES_CLUSTER,
taurus_star_at, aldebaran_at, alcyone_at,
stars_in_taurus,
)
from datetime import datetime, timezone
jd = utc_to_tt(jd_from_datetime(datetime(2026, 4, 7, tzinfo=timezone.utc)))
# By name via dispatcher:
ald = taurus_star_at(ALDEBARAN, jd)
print(f"Aldebaran: {ald.longitude:.4f}° mag {ald.magnitude}")
# Via convenience function:
alc = alcyone_at(jd)
# List all Taurus stars:
print(stars_in_taurus())
All position computation delegates to moira.stars.star_at — the constellation oracle adds no positional logic of its own.
18. Calendar & Time
from moira.facade import (
jd_from_datetime, datetime_from_jd, julian_day, calendar_from_jd,
calendar_datetime_from_jd, format_jd_utc, safe_datetime_from_jd,
greenwich_mean_sidereal_time, local_sidereal_time, delta_t,
CalendarDateTime,
)
| Function | Signature | Description |
|---|---|---|
jd_from_datetime | (dt: datetime) → float | timezone-aware datetime → UTC-coded civil JD; naïve datetimes raise ValueError |
datetime_from_jd | (jd: float) → datetime | UTC-coded civil JD → UTC datetime |
julian_day | (year, month, day, hour=0.0) → float | Calendar date → JD |
calendar_from_jd | (jd: float) → CalendarDateTime | JD → BCE-safe calendar breakdown |
calendar_datetime_from_jd | (jd: float) → CalendarDateTime | Alias for calendar_from_jd |
format_jd_utc | (jd: float) → str | Human-readable UTC string |
safe_datetime_from_jd | (jd: float) → datetime | None | Returns None for out-of-range JDs |
greenwich_mean_sidereal_time | (jd_ut: float) → float | GMST in degrees |
local_sidereal_time | (jd_ut, longitude, dpsi=None, obliq=None) → float | LAST in degrees |
delta_t | (year: float) → float | ΔT in seconds for a decimal year |
CalendarDateTime fields
| Field | Type | Description |
|---|---|---|
year | int | Proleptic Gregorian year (negative for BCE) |
month | int | Month (1–12) |
day | int | Day (1–31) |
hour | float | Decimal UT hour |
is_bce | bool | True when year < 1 (BCE convention) |
from moira.facade import jd_from_datetime, calendar_from_jd
import datetime
jd = jd_from_datetime(datetime.datetime(1988, 4, 4, 14, 30,
tzinfo=datetime.timezone.utc))
print(jd) # 2447255.104166...
cal = calendar_from_jd(jd)
print(cal.year, cal.month, cal.day, cal.hour)
# For BCE dates (negative year numbers):
jd_cleopatra = 1705426.0 # approx 69 BCE
cal2 = calendar_from_jd(jd_cleopatra)
print(cal2.is_bce, cal2.year) # True, -68 (astronomical year numbering)
Obliquity & nutation
from moira.facade import mean_obliquity, true_obliquity, nutation
# All take jd_tt (Terrestrial Time)
from moira.facade import jd_from_datetime
from moira.julian import utc_to_tt
jd_utc = jd_from_datetime(dt)
jd_tt = utc_to_tt(jd_utc)
obl_mean = mean_obliquity(jd_tt) # degrees
obl_true = true_obliquity(jd_tt) # degrees (mean + nutation correction)
dpsi, deps = nutation(jd_tt) # nutation in longitude and obliquity (arcsec)
Ayanamsa
from moira.facade import ayanamsa, tropical_to_sidereal, sidereal_to_tropical, list_ayanamsa_systems, Ayanamsa
offset = ayanamsa(jd_ut, Ayanamsa.LAHIRI) # degrees to subtract
sidereal_lon = tropical_to_sidereal(tropical_lon, jd_ut, Ayanamsa.LAHIRI)
tropical_lon = sidereal_to_tropical(sidereal_lon, jd_ut, Ayanamsa.LAHIRI)
all_systems = list_ayanamsa_systems() # list of all Ayanamsa.* constants
19. Policy Objects
Every computational pillar that has configurable behavior exposes a frozen dataclass policy. Policies use sensible defaults and can be constructed with keyword arguments for the parameters you want to override.
Pattern
# Using the default:
result = some_function(inputs)
# Customizing:
from moira.facade import AspectPolicy
policy = AspectPolicy(include_minor=False)
result = some_function(inputs, policy=policy)
Pillar policies reference
| Policy class | Module | Key parameters |
|---|---|---|
AspectPolicy | aspects | orb_table, min_tier, include_minor, motion_threshold |
HousePolicy | houses | polar_fallback, unknown_system |
DignityComputationPolicy | dignities | essential doctrine (traditional_classic_7 default, modern_co_rulers opt-in), mercury_sect_model, independent include_hayz / include_halb, include_oriental_occidental, solar condition, accidental dignity |
VedicDignityPolicy | vedic dignities | planetary friendship and compound-relationship policy |
AstrodynePolicy | Church of Light Astrodynes | fixed one-degree dignity band, magnitude parallels, Mercury two-stage orb, mutual-reception bonus |
LotsComputationPolicy | lots | reversal_kind, derived_reference, external_reference |
ProgressionComputationPolicy | progressions | time_key, direction, house_frame |
TransitComputationPolicy | transits | search, return_search, syzygy_search |
TransitSearchPolicy | transits | step_days, max_iterations, exact_threshold |
SynastryComputationPolicy | synastry | aspect_policy, overlay_policy, composite_policy, davison_policy |
JaiminiPolicy | jaimini | karaka assignment and tie-break policy |
PanchangaPolicy | panchanga | panchanga computation and classification policy |
AshtottariPolicy | alternate dasha | Ashtottari year-basis and sequence policy |
YoginiPolicy | alternate dasha | Yogini year-basis and sequence policy |
AshtakavargaPolicy | ashtakavarga | shodhana and sign-strength interpretation policy |
ShadbalaPolicy | shadbala | sufficiency thresholds and component interpretation policy |
PatternComputationPolicy | patterns | selection, stellium, orb_factor, dominant_only |
TimelordComputationPolicy | timelords | firdaria_year_policy, zr_year_policy |
VimshottariComputationPolicy | dasha | year_policy, ayanamsa_policy |
FixedStarComputationPolicy | fixed_stars | lookup_policy, heliacal_search_policy |
VarStarPolicy | variable_stars | eclipse_threshold |
UnifiedStarComputationPolicy | stars | merge_policy |
SothicComputationPolicy | sothic | calendar_policy, heliacal_policy, epoch_policy |
Doctrine constants
from moira.facade import CANONICAL_ASPECTS, DEFAULT_POLICY, ASPECT_TIERS
from moira.facade import FIRDARIA_DIURNAL, FIRDARIA_NOCTURNAL, FIRDARIA_NOCTURNAL_BONATTI
from moira.facade import CHALDEAN_ORDER, MINOR_YEARS
from moira.facade import VIMSHOTTARI_YEARS, VIMSHOTTARI_SEQUENCE, VIMSHOTTARI_TOTAL
from moira.facade import VIMSHOTTARI_YEAR_BASIS, VIMSHOTTARI_LEVEL_NAMES
from moira.facade import EGYPTIAN_MONTHS, EGYPTIAN_SEASONS, EPAGOMENAL_BIRTHS
from moira.facade import HISTORICAL_SOTHIC_EPOCHS
from moira.facade import CIRCLE_TYPES, DEFAULT_PARAN_POLICY
from moira.facade import HARMONIC_PRESETS, MANSIONS
20. moira.sky — Strict Astronomy API
moira.sky is a sovereign astronomical computation surface. Every quantity is derived from Moira's own verified pipeline — the DE441 ephemeris, IAU 2006 precession, IAU 2000A nutation, and IERS ΔT. It exposes the low-level astronomy substrate that underpins the astrological tier modules without any application-layer coupling.
import moira.sky
from moira.sky import time, position, frames, visibility
from moira.sky import bodies, observation, galactic, events, eclipse, occultation
Each submodule is a self-contained import surface. Submodules do not import from each other.
Note: Submodules marked
[stub]in themoira.skypackage docstring raiseNotImplementedErrorfor functions not yet fully implemented. They are documented and importable, but do not silently return incorrect results.
moira.sky.time — Time Systems and ΔT
from moira.sky.time import (
CalendarDateTime, julian_day, calendar_from_jd, calendar_datetime_from_jd,
jd_from_datetime, decimal_year, decimal_year_from_jd, centuries_from_j2000,
utc_to_tt, utc_to_ut1, ut_to_tt, tt_to_ut, tt_to_tdb,
earth_rotation_angle, greenwich_mean_sidereal_time,
apparent_sidereal_time, apparent_sidereal_time_at, local_sidereal_time,
DeltaTPolicy, delta_t, delta_t_from_jd,
DeltaTBreakdown, DeltaTDistribution,
delta_t_breakdown, delta_t_distribution,
secular_trend, core_delta_t, cryo_delta_t, fluid_lowfreq,
)
Calendar and Julian Day
| Function | Signature | Description |
|---|---|---|
julian_day | (year, month, day, hour=0.0) → float | Calendar date → JD |
calendar_from_jd | (jd: float) → CalendarDateTime | JD → BCE-safe calendar breakdown |
calendar_datetime_from_jd | (jd: float) → CalendarDateTime | Alias for calendar_from_jd |
jd_from_datetime | (dt: datetime) → float | timezone-aware datetime → UTC-coded civil JD; naïve datetimes raise ValueError |
decimal_year | (year, month=1) → float | NASA-compatible month-midpoint decimal year |
decimal_year_from_jd | (jd: float) → float | JD → NASA-compatible month-midpoint decimal year |
centuries_from_j2000 | (jd_tt: float) → float | Julian centuries from J2000.0 |
Time scale conversions
| Function | Signature | Description |
|---|---|---|
utc_to_tt | (jd_utc: float) → float | UTC → TT through TAI and the leap-second table |
utc_to_ut1 | (jd_utc: float) → float | UTC → UT1 through admitted DUT1 data, with explicit historical/fallback policy |
ut_to_tt | (jd_ut: float) → float | UT1 → Terrestrial Time (adds ΔT) |
tt_to_ut | (jd_tt: float) → float | TT → UT1 |
tt_to_tdb | (jd_tt: float) → float | TT → Barycentric Dynamical Time |
Hybrid and physical JD transforms use an exact private fraction between
successive January 1 boundaries; they do not use the public NASA
month-midpoint coordinate. Before the final civil day of 1971, civil JDs retain
Moira's historical UT1-proxy interpretation. That final day uses a monotonic
smoothstep into the 1972-01-01 atomic rule, with the private inverse solving
the same handoff. Private UT1-to-UTC formatting inverts the within-day UT1-TAI
relation so a positive leap second is not smeared across the preceding day.
Earth rotation and sidereal time
| Function | Signature | Description |
|---|---|---|
earth_rotation_angle | (jd_ut: float) → float | ERA in degrees |
greenwich_mean_sidereal_time | (jd_ut: float) → float | GMST in degrees |
apparent_sidereal_time | (jd_ut: float) → float | GAST in degrees |
apparent_sidereal_time_at | (jd_ut, dpsi, obliq) → float | GAST with supplied nutation terms |
local_sidereal_time | (jd_ut, longitude, dpsi=None, obliq=None) → float | LAST in degrees |
ΔT — standard
| Function | Signature | Description |
|---|---|---|
delta_t | (year: float) → float | Source-priority ΔT in seconds for a decimal year, preserving each admitted source's published basis |
delta_t_from_jd | (jd_ut: float) → float | ΔT in seconds from a UT1 JD; admitted EOP rows govern in coverage, outer reconciliation tapers locally over one Julian year, and internal gaps reconcile only their boundaries |
ΔT — source-priority accounting and scenario policy
bd = delta_t_breakdown(year)
dist = delta_t_distribution(year)
| Function | Signature | Description |
|---|---|---|
delta_t_breakdown | (year: float) → DeltaTBreakdown | Source/scenario total in the stable additive accounting vessel |
delta_t_distribution | (year: float) → DeltaTDistribution | Mean plus source-error or uncalibrated policy scale in a normal-shaped convenience vessel |
secular_trend | (year: float) → float | Compatibility helper for the declared future curvature scenario |
core_delta_t | (year: float) → float | Compatibility surface; zero while the C04 proxy is quarantined |
cryo_delta_t | (year: float) → float | Compatibility surface; zero while the GRACE derivative is quarantined |
fluid_lowfreq | (year: float) → float | Compatibility surface; zero while AAM/OAM proxies are quarantined |
Generic delta_t() preserves the raw HPIERS DE430/LE430 source basis; it does
not ambiently retarget the clock product to DE441. From -2100 to the first
HPIERS row at -2000, it exposes an explicit 100-year C0 source-floor bridge.
The physical-policy surface is admitted from decimal year -2000.0; earlier
physical requests raise ValueError. Through the final aggregate
representative epoch (currently 2026.123287671233) the total follows admitted
source tables. That final value is a Jan–Apr partial mean, and the slope formed
from the 2025 and 2026 aggregate representative epochs is provisional
scenario policy rather than an observed instantaneous derivative. After that
source-owned boundary the mean is the explicit boundary-anchored scenario
documented in DELTA_T_HYBRID_MODEL.md. Values beyond 2150 remain computable
scenario extrapolations, not authority-validated forecasts.
Packaged EOP rows are runtime-admitted, but the transform did not retain their
source observed/predicted flags, so they must not all be called measured or
definitive observations. Generic Delta-T years are computationally guarded to
[-100000, +100000]; JD-aware time transforms are guarded to
[-40000000, +40000000]. These are representability limits, not scientific
coverage claims.
DeltaTBreakdown fields
| Field | Type | Description |
|---|---|---|
year | float | Decimal year requested |
total | float | Total ΔT in seconds |
secular | float | Declared curvature baseline; not a measured causal decomposition in source-backed eras |
core | float | Reserved compatibility component; currently zero |
cryo | float | Reserved compatibility component; currently zero |
fluid | float | Reserved compatibility component; currently zero |
bridge | float | Explicit arithmetic reconciliation from the curvature baseline to the admitted total or boundary-conditioned scenario |
residual | float | Reserved compatibility component; currently zero |
era | str | Compatibility category: pre-1840, historical, measured, or future; not source-row provenance |
The additive invariant is
secular + core + cryo + fluid + bridge + residual == total.
DeltaTDistribution fields and methods
| Member | Type | Description |
|---|---|---|
year | float | Decimal year requested |
mean | float | Same mean returned by the physical-policy total |
sigma | float | HPIERS source-error scale where aligned with that source; otherwise a modern floor or uncalibrated future policy scale in seconds |
variance | float | sigma² |
pdf(delta_t_seconds) | float | Normal-approximation density |
interval(sigma=1.0) | tuple[float, float] | Symmetric policy interval around the mean |
The normal vessel is a computational approximation. It does not assert that ancient or future Earth-rotation errors are empirically Gaussian. Future values do not have calibrated coverage and do not propagate unquantified uncertainty in the handoff value or final-row slope.
moira.sky.position — Astrometric Correction Pipeline
from moira.sky.position import (
apply_light_time, apply_aberration, apply_deflection, apply_frame_bias,
topocentric_correction, apply_refraction,
atmospheric_refraction, atmospheric_refraction_extended,
)
The five-stage pipeline converts geometric ICRF coordinates into observable apparent positions. Apply corrections in the order listed:
| Stage | Function | Description |
|---|---|---|
| 1 | apply_light_time(body, jd_tt, reader, earth_ssb, barycentric_fn) | Iterative geometric delay; returns (corrected_xyz: Vec3, light_time_days: float) |
| 2 | apply_aberration(xyz, observer_vel) | Relativistic stellar aberration due to observer velocity |
| 3 | apply_deflection(xyz, jd_tt, reader) | Gravitational light deflection by Sun, Jupiter, and Saturn |
| 4 | apply_frame_bias(xyz) | IAU 2006 FK5/ICRS frame alignment (~17 mas offset) |
| 5 | topocentric_correction(xyz_gcrs, jd_tt, lat, lon, elev_m=0.0) | WGS-84 observer parallax shift |
Atmospheric refraction (applied after stage 5):
| Function | Signature | Description |
|---|---|---|
apply_refraction(alt_deg, policy) | → float | Apply the policy-selected refraction model to an altitude in degrees |
atmospheric_refraction(altitude_deg) | → float | Bennett (1982) refraction in arcminutes — fast, altitude only |
atmospheric_refraction_extended(altitude_deg, temperature_C, pressure_mbar, humidity, wavelength_um, elevation_m) | → float | Full physical refraction model |
moira.sky.frames — Coordinate Frame Transforms
from moira.sky.frames import (
Vec3, Mat3,
icrf_to_ecliptic, icrf_to_true_ecliptic, true_ecliptic_latitude, icrf_to_equatorial,
ecliptic_to_equatorial, equatorial_to_ecliptic,
equatorial_to_horizontal, horizontal_to_equatorial,
precession_matrix_equatorial, nutation_matrix_equatorial,
rot_x, rot_y, rot_z,
cotrans_sp, aberration_correction,
normalize_degrees, angular_distance, signed_angular_distance,
equation_of_time,
LocalSpacePosition, local_space_positions,
)
Vec3 = tuple[float, float, float] — Cartesian triple or angular triple.
Mat3 = tuple[Vec3, Vec3, Vec3] — 3×3 rotation matrix as three row vectors.
Direct frame transforms
| Function | Signature | Description |
|---|---|---|
icrf_to_ecliptic | (xyz: Vec3, obliquity: float) → (lon, lat) | ICRF Cartesian → ecliptic lon/lat using supplied obliquity (degrees) |
icrf_to_true_ecliptic | (xyz: Vec3, jd_tt: float) → (lon, lat) | ICRF → true ecliptic with full precession + nutation |
true_ecliptic_latitude | (xyz: Vec3, jd_tt: float) → float | Ecliptic latitude only (P+N applied) |
icrf_to_equatorial | (xyz: Vec3) → (ra_rad, dec_rad) | ICRF Cartesian → RA/Dec in radians |
ecliptic_to_equatorial | (lon, lat, obliquity) → (ra, dec) | Ecliptic → equatorial (degrees) |
equatorial_to_ecliptic | (ra, dec, obliquity) → (lon, lat) | Equatorial → ecliptic (degrees) |
equatorial_to_horizontal | (ra, dec, lst, lat) → (az, alt) | Equatorial → azimuth/altitude; azimuth 0=N, 90=E |
horizontal_to_equatorial | (az, alt, lst, lat) → (ra, dec) | Horizontal → equatorial (degrees) |
Rotation matrices
| Function | Signature | Description |
|---|---|---|
precession_matrix_equatorial | (jd_tt: float) → Mat3 | IAU 2006 precession rotation matrix |
nutation_matrix_equatorial | (jd_tt: float) → Mat3 | IAU 2000A nutation rotation matrix |
rot_x / rot_y / rot_z | (angle_rad: float) → Mat3 | Single-axis rotation matrices (astronomical sign convention) |
cotrans_sp | (xyz: Vec3, matrix: Mat3) → Vec3 | Apply a rotation matrix to a Cartesian triple |
aberration_correction | (xyz: Vec3, observer_vel: Vec3) → Vec3 | Annual aberration (geometric model) |
Utility
| Function | Signature | Description |
|---|---|---|
normalize_degrees | (deg: float) → float | Fold angle into [0, 360) |
angular_distance | (a, b: float) → float | Unsigned shortest arc between two angles (degrees) |
signed_angular_distance | (a, b: float) → float | Signed angular difference (degrees) |
equation_of_time | (jd_tt: float) → float | Solar time correction in minutes |
Horizon frame — batch
from moira.sky.frames import local_space_positions, LocalSpacePosition
positions = local_space_positions(chart_positions, jd_ut, lat, lon, reader)
# list[LocalSpacePosition] — each has .azimuth, .altitude, .is_above, .compass_direction()
moira.sky.bodies — Celestial Body Positions
from moira.sky.bodies import (
PlanetData, SkyPosition, HeliocentricData, CartesianPosition,
SSBPosition, SSB_BODIES, PlanetocentricData, VALID_OBSERVER_BODIES,
NodeData, NodesAndApsides,
planet_at, sky_position_at, all_planets_at, sun_longitude,
planet_relative_to, next_heliocentric_transit,
heliocentric_planet_at, all_heliocentric_at,
ssb_position_at, all_ssb_positions_at,
planetocentric_at, all_planetocentric_at,
mean_node, true_node, mean_lilith, true_lilith,
next_moon_node_crossing, nodes_and_apsides_at,
)
| Function | Returns | Description |
|---|---|---|
planet_at(body, jd_ut, reader=None, ...) | PlanetData | Geocentric ecliptic position |
sky_position_at(body, jd_ut, observer_lat, observer_lon, observer_elev_m=0.0, reader=None) | SkyPosition | Topocentric apparent RA/Dec + alt/az |
all_planets_at(jd_ut, bodies=None, reader=None) | dict[str, PlanetData] | All planets at one epoch |
sun_longitude(jd_ut, reader=None) | float | Solar ecliptic longitude (geocentric, true-of-date) |
planet_relative_to(body, jd_ut, reference) | PlanetData | Body position measured from reference body |
next_heliocentric_transit(body, jd_start, longitude) | float | Next JD when body's heliocentric longitude equals target |
heliocentric_planet_at(body, jd_ut, reader=None) | HeliocentricData | Heliocentric ecliptic position |
all_heliocentric_at(jd_ut, bodies=None, reader=None) | dict[str, HeliocentricData] | All planets heliocentrically |
ssb_position_at(body, jd_ut, reader=None) | SSBPosition | SSB-origin ecliptic position in true-of-date orientation |
all_ssb_positions_at(jd_ut, reader=None) | dict[str, SSBPosition] | All SSB_BODIES from SSB |
planetocentric_at(observer_body, target_body, jd_ut) | PlanetocentricData | Geometric target position measured from the center of observer body |
all_planetocentric_at(observer_body, jd_ut) | dict[str, PlanetocentricData] | All targets from observer body |
mean_node(jd_ut, *, nutation=True) | NodeData | IERS 2003 mean lunar ascending node; true equinox of date by default |
true_node(jd_ut, reader=None) | NodeData | True (osculating) ascending node |
mean_lilith(jd_ut, *, nutation=True) | NodeData | Mean Black Moon Lilith (mean apogee); true equinox of date by default |
true_lilith(jd_ut) | NodeData | True Lilith (osculating apogee) |
next_moon_node_crossing(jd_start, reader=None, ascending=True) | float | Next Moon ecliptic crossing (JD UT) |
nodes_and_apsides_at(jd_ut) | NodesAndApsides | Combined node/apsides vessel (mean/true node, Lilith, perigee, apogee) |
Note:
moira.sky.bodiesis the strict astronomy surface for solar system bodies. Asteroids, Uranian planets, and fixed stars are not included; usemoira.facadefor those.
moira.sky.observation — Observational Quantities and Phenomena
from moira.sky.observation import (
phase_angle, illuminated_fraction, elongation,
synodic_phase_angle, synodic_phase_state,
angular_diameter, apparent_magnitude,
PhenomenonEvent, OrbitalResonance, PlanetPhenomena, MOON_PHASE_ANGLES,
greatest_elongation, perihelion, aphelion,
next_moon_phase, moon_phases_in_range,
next_conjunction, conjunctions_in_range,
resonance, planet_phenomena_at,
)
Phase quantities
| Function | Signature | Description |
|---|---|---|
phase_angle(body, jd_ut) | → float | Sun–Planet–Earth angle in degrees |
illuminated_fraction(phase_angle) | → float | Illuminated disk fraction (0.0–1.0) |
elongation(body, jd_ut) | → float | Angular separation from the Sun (0°–180°) |
synodic_phase_angle(body1, body2, jd_ut) | → float | Ecliptic phase angle between any two bodies (0°–360°) |
synodic_phase_state(angle_deg) | → str | Coarse phase label (e.g. "waxing", "full", "waning") |
angular_diameter(body, jd_ut) | → float | Apparent angular diameter in arcseconds |
apparent_magnitude(body, jd_ut) | → float | Apparent visual magnitude (V band) |
Phenomena search
| Function | Signature | Description |
|---|---|---|
greatest_elongation(body, jd_start) | → PhenomenonEvent | Next greatest elongation of Mercury or Venus |
perihelion(body, jd_start) | → PhenomenonEvent | Next perihelion passage |
aphelion(body, jd_start) | → PhenomenonEvent | Next aphelion passage |
next_moon_phase(phase_name, jd_start) | → float | Next named Moon phase (JD UT); keys from MOON_PHASE_ANGLES |
moon_phases_in_range(jd_start, jd_end) | → list[PhenomenonEvent] | All eight Moon phases in a date range |
next_conjunction(body1, body2, jd_start) | → PhenomenonEvent | Next geocentric conjunction |
conjunctions_in_range(body1, body2, jd_start, jd_end) | → list[PhenomenonEvent] | All conjunctions in a date range |
resonance(body1, body2) | → OrbitalResonance | Best harmonic ratio P/Q between sidereal periods |
planet_phenomena_at(body, jd_ut) | → PlanetPhenomena | Full phenomena snapshot at epoch |
MOON_PHASE_ANGLES — dict mapping phase name → target elongation:
new_moon, first_quarter, full_moon, last_quarter, waxing_crescent, waxing_gibbous, waning_gibbous, waning_crescent.
moira.sky.galactic — Galactic Coordinate System
from moira.sky.galactic import (
GalacticPosition,
equatorial_to_galactic, galactic_to_equatorial,
ecliptic_to_galactic, galactic_to_ecliptic,
galactic_reference_points, galactic_position_of, all_galactic_positions,
)
Rotation matrix authority: Liu, Zhu & Zhang (2011, A&A 526, A16) — IAU 1958 galactic pole definition rigorously tied to ICRS/J2000. Galactic longitude increases eastward; 0° points toward the Galactic Center.
| Function | Signature | Description |
|---|---|---|
equatorial_to_galactic(ra_deg, dec_deg) | → (l, b) | RA/Dec → galactic l/b (J2000, degrees) |
galactic_to_equatorial(l_deg, b_deg) | → (ra, dec) | Galactic l/b → RA/Dec (J2000, degrees) |
ecliptic_to_galactic(lon, lat, obliquity, jd_tt) | → (l, b) | Ecliptic → galactic (bridges via equatorial) |
galactic_to_ecliptic(l, b, obliquity, jd_tt) | → (lon, lat) | Galactic → ecliptic (bridges via equatorial) |
galactic_reference_points(obliquity, jd_tt) | → dict[str, (lon, lat)] | Ecliptic coordinates of GC, NGP, GAC, SGP, SGC at the given epoch |
galactic_position_of(body, jd_ut, ...) | → GalacticPosition | GalacticPosition for one body |
all_galactic_positions(chart_lons, jd_ut, ...) | → list[GalacticPosition] | GalacticPosition for all bodies in a chart |
Named reference points: GC (Galactic Center / Sgr A*), NGP (North Galactic Pole, Coma Berenices), GAC (Galactic Anti-Center, Gemini/Auriga), SGP (South Galactic Pole), SGC (Super-Galactic Center, Virgo/M87).
moira.sky.events — Rise, Set, Transit, Twilight, and Stations
from moira.sky.events import (
RiseSetPolicy, TwilightTimes,
find_phenomena, get_transit, twilight_times,
StationEvent, find_stations, next_station, is_retrograde, retrograde_periods,
)
Rise / set / transit / twilight
| Function | Signature | Description |
|---|---|---|
find_phenomena(body, jd_day, lat, lon, policy) | → dict | Rise, set, transit dict with JD_UT values (or None when event does not occur that day) |
get_transit(body, jd_day, lat, lon, upper=True) | → float | JD_UT of upper (or lower) meridian transit |
twilight_times(jd_day, lat, lon) | → TwilightTimes | Civil / nautical / astronomical twilight table for a day and location |
TwilightTimes fields
| Field | Description |
|---|---|
civil_dusk, civil_dawn | Sun at −6° |
nautical_dusk, nautical_dawn | Sun at −12° |
astro_dusk, astro_dawn | Sun at −18° |
sunset, sunrise | Limb at geometric horizon |
solar_noon | Upper meridian transit |
Stations
| Function | Signature | Description |
|---|---|---|
find_stations(body, jd_start, jd_end) | → list[StationEvent] | All SR/SD stations for a body in a date range |
next_station(body, jd_start) | → StationEvent | First station (SR or SD) after jd_start |
is_retrograde(body, jd_ut) | → bool | True if the body is retrograde at the given epoch |
retrograde_periods(body, jd_start, jd_end) | → list[tuple[float, float]] | (jd_SR, jd_SD) pairs — begin and end of each retrograde arc |
StationEvent fields: body, kind ("SR" = stationary retrograde / "SD" = stationary direct), jd_ut, datetime (UTC), longitude.
moira.sky.eclipse — Solar and Lunar Eclipses
from moira.sky.eclipse import (
EclipseCalculator, EclipseType,
EclipseData, EclipseEvent,
SolarBesselianElements,
SolarEclipseFootprintBoundaryKind, SolarEclipsePenumbralContactKind,
SolarEclipseFootprintTopology, SolarEclipseFootprintPoint,
SolarEclipsePenumbralContact, SolarEclipseFootprintContacts,
SolarEclipseLimitTrack, SolarEclipseVisibilityFootprint,
EclipseEpoch, EclipseGeocentricBodyState,
SolarEclipseGlobalCircumstances, SolarEclipseCartography,
LunarEclipseGlobalCircumstances,
SolarEclipsePath, SolarEclipseLocalCircumstances,
SolarBodyCircumstances, LocalContactCircumstances,
LunarEclipseAnalysis, LunarEclipseLocalCircumstances, LunarEclipseContacts,
LunarEclipseVisibilityContactKind, LunarEclipseVisibilityPoint,
LunarEclipseVisibilityLimit, LunarEclipseVisibilityMap,
next_solar_eclipse_at_location, find_lunar_contacts,
)
Primary engine
calc = EclipseCalculator()
jd_start = 2460676.5
lat, lon = 40.7, -74.0
# Solar eclipse search and local circumstances
ev = calc.next_solar_eclipse(jd_start, kind="any")
circ = calc.solar_local_circumstances(
jd_start, lat, lon, elevation_m=0.0, kind="any"
)
path = calc.solar_eclipse_path(jd_start, kind="any", sample_count=9)
footprint = calc.solar_eclipse_footprint(
jd_start, kind="any", sample_count=181
)
solar_global = calc.solar_global_circumstances(jd_start, kind="any")
solar_map = calc.solar_eclipse_cartography(
jd_start,
kind="any",
magnitude_levels=(0.2, 0.4, 0.6, 0.8, 0.9),
obscuration_levels=(0.2, 0.4, 0.6, 0.8, 0.9),
mesh_depth=1,
time_samples=17,
angular_tolerance_deg=8.0,
field_tolerance=0.01,
)
full = calc.next_solar_eclipse_at_location(
jd_start, lat, lon, elevation_m=0.0, kind="any"
) # search + circumstances combined
# Lunar eclipse search and analysis
lunar_event = calc.next_lunar_eclipse(jd_start, kind="any")
ana = calc.analyze_lunar_eclipse(jd_start, kind="any", mode="native")
nasa_ana = calc.analyze_lunar_eclipse(
jd_start, kind="any", mode="nasa_compat"
)
lc = calc.lunar_local_circumstances(
jd_start, lat, lon, elevation_m=0.0, kind="any", mode="native"
)
lunar_map = calc.lunar_eclipse_visibility_map(
jd_start, kind="any", mode="native", sample_count=181
)
lunar_global = calc.lunar_global_circumstances(
jd_start, kind="any", mode="native"
)
# Inclusive bulk ranges (global maxima in UT1)
solar_range = calc.solar_eclipses_in_range(jd_start, jd_start + 3652.5)
lunar_range = calc.lunar_eclipses_in_range(jd_start, jd_start + 3652.5)
# Geometry snapshot at any epoch
snap = calc.calculate_jd(jd_start) # → EclipseData
solar_eclipses_in_range(jd_start, jd_end) and
lunar_eclipses_in_range(jd_start, jd_end) include maxima on both interval
boundaries and return time-ordered EclipseEvent lists. With a compatible
content-identified planetary reader, C++ scans a padded TT interval for a
conservative two-degree syzygy-candidate superset. Python remains authoritative
for reader-bound TT/UT1 conversion, physical maximum refinement, eclipse
classification, deduplication, inclusive filtering, and public vessel assembly.
If one native evaluator cannot cover the padded interval, the same methods use
the explicit Python manuscript. The older native generic-event scanners are not
used as public classification or contact products.
Lunar visibility-map engine signatures
| Surface | Exact signature | Returns |
|---|---|---|
EclipseCalculator | lunar_eclipse_visibility_map(jd_start, *, kind="any", backward=False, mode="native", sample_count=181) | LunarEclipseVisibilityMap |
Moira facade | lunar_eclipse_visibility_map(jd_start, *, kind="any", backward=False, mode="native", sample_count=181) | LunarEclipseVisibilityMap |
The map contains one LunarEclipseVisibilityLimit for every contact that
exists for the selected eclipse, in chronological order. Each limit carries
its contact kind, UT1 epoch, closed geographic ring, and sublunar point; the
visible side is the side containing the sublunar point. Total eclipses expose
P1/U1/U2/greatest/U3/U4/P4, partial eclipses omit U2/U3, and penumbral-only
eclipses expose P1/greatest/P4.
The boundary is an exact ellipsoid-tangency product in scaled WGS-84 space, using the retarded DE441/LE441 Moon-center reception vector. It deliberately excludes atmosphere, terrain, observer elevation, and lunar-limb relief and therefore does not replace observer-local apparent circumstances. The Python layer owns contact policy and public semantics; no native C++ port is used for this seven-contact assembly.
Global-circumstances and cartography signatures
| Surface | Exact signature | Returns |
|---|---|---|
EclipseCalculator / Moira | solar_global_circumstances(jd_start, *, kind="any", backward=False) | SolarEclipseGlobalCircumstances |
EclipseCalculator / Moira | solar_eclipse_cartography(jd_start, *, kind="any", backward=False, magnitude_levels=(0.2, 0.4, 0.6, 0.8, 0.9), obscuration_levels=(0.2, 0.4, 0.6, 0.8, 0.9), mesh_depth=1, time_samples=17, angular_tolerance_deg=8.0, field_tolerance=0.01) | SolarEclipseCartography |
EclipseCalculator / Moira | lunar_global_circumstances(jd_start, *, kind="any", backward=False, mode="native") | LunarEclipseGlobalCircumstances |
Solar global circumstances distinguish greatest eclipse from greatest duration,
carry separate equatorial/ecliptic conjunction epochs, expose U1-U4 only for
central events, and preserve explicit TT/UT1/Delta-T metadata. Lunar global
circumstances retain mode-pure shadow geometry, contacts, phase durations, and
geocentric body parameters. The cartography method emits observer-local maximum
magnitude and obscuration as distinct contour families. Contour identity is
(component_id, segment_id); antimeridian splits are open transport-safe
segments of one spherical component. Duration contours are not admitted.
The result reports the achieved conforming refinement depth, triangle count,
maximum angular edge, and unresolved-edge convergence state.
Solar footprint engine signatures
| Surface | Exact signature | Returns |
|---|---|---|
EclipseCalculator | solar_eclipse_footprint(jd_start, *, kind="any", backward=False, sample_count=181) | SolarEclipseVisibilityFootprint |
Moira facade | solar_eclipse_footprint(jd_start, *, kind="any", backward=False, sample_count=181) | SolarEclipseVisibilityFootprint |
kind accepts "any", "total", "annular", "partial", "central",
or "hybrid". sample_count is an integer in 9..721; it controls only
presentation density. The governing solve, contacts, horizon incidences,
temporal folds, and (kind, component_id, segment_id) graph do not change
with that requested density.
Solar footprint vessel contract
| Vessel | Fields |
|---|---|
SolarEclipseFootprintPoint | jd_ut, latitude_deg, longitude_deg; computed datetime_utc and BCE-safe calendar_utc |
SolarEclipsePenumbralContact | kind, point |
SolarEclipseFootprintContacts | required p1/p4, paired optional p2/p3 |
SolarEclipseLimitTrack | kind, component_id, segment_id, immutable time-ordered points |
SolarEclipseVisibilityFootprint | event, greatest, topology, contacts, tracks, ephemeris, surface_model, limb_model, time_scale, atmospheric_refraction |
Boundary kinds are penumbral_north, penumbral_south, sunrise, and
sunset. Every penumbral kind admitted by the topology contains exactly one
connected component, identified as component_id=0. A component that folds in
UT1 is emitted as strictly time-ordered tracks with contiguous segment_id
values 0..n-1; adjacent folded segments share the solver-refined fold point.
Each penumbral component has exactly two incidences on the sunrise/sunset
graph. In two_limit_two_loop, the north and south incidence sets are
disjoint, the event is globally central rather than partial, and every horizon
track lies wholly within P1-P2 or P3-P4 rather than crossing P2-P3. Topology is
one_limit_connected or two_limit_two_loop.
Convenience function
from moira.sky.eclipse import next_solar_eclipse_at_location
result = next_solar_eclipse_at_location(
jd_start, lat, lon, elevation_m=0.0, kind="any", max_lunations=360
)
Key vessel fields
EclipseData: eclipse_type, eclipse_magnitude, saros_index, metonic_year, metonic_is_reset, moon_parallax, solar_diameter, moon_diameter, separation, phase_angle.
EclipseEvent: jd_ut, eclipse_type, datetime_utc (computed property).
LunarEclipseContacts: precise UT1 contact times P1 (1st penumbral), U1 (1st umbral), U2 (start of totality), U3 (end of totality), U4 (last umbral), P4 (last penumbral), plus the separate greatest-eclipse instant.
For mode="nasa_compat", LunarEclipseAnalysis.canon_method is
nasa_shadow_axis_apparent_sun_moon; source_model names the same declared
reduction. Native mode and its contact policy are unchanged.
Note:
next_solar_eclipse_at_locationis also available directly frommoira.facadeandmoira.eclipse. It is not re-exported throughmoira.predictive.
moira.sky.occultation — Occultations, Grazes, and Close Approaches
from moira.sky.occultation import (
CloseApproach, LunarOccultation, OccultationPathGeometry, OccultationPathTopology,
OccultationPathPoint, OccultationPathBoundaryPoint, OccultationPathBoundaryTrack,
OccultationPathBoundarySide, OccultationPathTopologyKind,
OccultationGeographicPole, OccultationPoleCrossingPhase, OccultationPoleCrossing,
GrazeCircumstances, GrazeTableRow, GrazeProductGeometry, GrazeProductTrack,
close_approaches, lunar_occultation, lunar_occultation_path_at, lunar_occultation_path,
lunar_occultation_path_topology_at, lunar_occultation_path_topology,
all_lunar_occultations,
lunar_star_occultation, lunar_star_occultation_path_at, lunar_star_occultation_path,
lunar_star_occultation_path_topology_at, lunar_star_occultation_path_topology,
lunar_star_graze_circumstances, lunar_star_graze_latitude,
lunar_star_practical_graze_latitude, lunar_star_graze_line,
lunar_star_graze_table, lunar_star_graze_product_at, lunar_star_graze_product_track,
)
| Function | Signature | Description |
|---|---|---|
close_approaches(body1, body2, jd_start, jd_end) | → list[CloseApproach] | All minimum-separation events between two bodies |
lunar_occultation(body, jd_start, jd_end) | → list[LunarOccultation] | Moon occultations of a named planet |
all_lunar_occultations(jd_start, jd_end, planets=None, reader=None) | → list[LunarOccultation] | Occultations of the default visible-planet set or caller-supplied targets |
lunar_occultation_path_at(target, jd_mid, *, sample_count=9, observer_elev_m=0.0, limb_profile_provider=None, reader=None) | → OccultationPathGeometry | Compatibility center/width/duration summary at a supplied greatest epoch |
lunar_occultation_path(target, jd_start, jd_end, step_days=0.25, sample_count=9, observer_elev_m=0.0, limb_profile_provider=None, reader=None) | → list[OccultationPathGeometry] | Compatibility summaries for planetary events in a search interval |
lunar_occultation_path_topology_at(target, jd_mid) | → OccultationPathTopology | Polar-safe planetary path band at one greatest epoch |
lunar_occultation_path_topology(target, jd_start, jd_end) | → list[OccultationPathTopology] | Detailed planetary path bands in a search interval |
lunar_star_occultation(star, jd_start, jd_end) | → list[LunarOccultation] | Moon occultations of a named fixed star |
lunar_star_occultation_path_at(star_lon, star_lat, star_name, jd_mid, *, sample_count=9, observer_elev_m=0.0, limb_profile_provider=None, reader=None) | → OccultationPathGeometry | Compatibility center/width/duration summary at a supplied greatest epoch |
lunar_star_occultation_path(star_lon, star_lat, star_name, jd_start, jd_end, step_days=0.25, sample_count=9, observer_elev_m=0.0, limb_profile_provider=None, reader=None) | → list[OccultationPathGeometry] | Compatibility summaries for fixed-star events in a search interval |
lunar_star_occultation_path_topology_at(star_lon, star_lat, star_name, jd_mid) | → OccultationPathTopology | Polar-safe fixed-star path band at one greatest epoch |
lunar_star_occultation_path_topology(star_lon, star_lat, star_name, jd_start, jd_end) | → list[OccultationPathTopology] | Detailed fixed-star path bands in a search interval |
lunar_star_graze_table(star, event) | → list[GrazeTableRow] | Latitude-keyed graze contact table |
lunar_star_graze_product_track(star, event) | → GrazeProductTrack | Full graze track across a latitude band |
moira.sky.visibility — Observational Visibility Doctrine
from moira.sky.visibility import (
HeliacalEventKind, VisibilityTargetKind, LightPollutionClass,
LightPollutionDerivationMode, ObserverAid, VisibilityCriterionFamily,
LunarCrescentVisibilityClass, VisibilityExtinctionModel, VisibilityTwilightModel,
MoonlightPolicy,
ExtinctionCoefficient, ObserverVisibilityEnvironment,
VisibilityPolicy, VisibilitySearchPolicy, VisibilityModel, HeliacalPolicy,
LunarCrescentDetails, VisibilityAssessment,
GeneralVisibilityEvent, PlanetHeliacalEvent,
visibility_assessment, visual_limiting_magnitude, visibility_event,
planet_heliacal_rising, planet_heliacal_setting,
planet_acronychal_rising, planet_acronychal_setting,
)
| Function | Signature | Description |
|---|---|---|
visibility_assessment(body, jd_ut, lat, lon, *, policy=None) | → VisibilityAssessment | Single-epoch observability check |
visual_limiting_magnitude(jd_ut, lat, lon, *, policy=None) | → float | Effective limiting magnitude for the observer/epoch |
visibility_event(body, event_kind, jd_start, lat, lon, *, heliacal_policy=None, ...) | → GeneralVisibilityEvent | None | Search for next heliacal event |
planet_heliacal_rising(body, jd_start, lat, lon, ...) | → PlanetHeliacalEvent | None | Morning first visibility |
planet_heliacal_setting(body, jd_start, lat, lon, ...) | → PlanetHeliacalEvent | None | Evening last visibility |
planet_acronychal_rising(body, jd_start, lat, lon, ...) | → PlanetHeliacalEvent | None | Evening first visibility |
planet_acronychal_setting(body, jd_start, lat, lon, ...) | → PlanetHeliacalEvent | None | Morning last visibility |
LunarCrescentVisibilityClass values: A (easily visible), B (visible under perfect conditions), C (may need optical aid), D (only with optical aid), E (not with optical aid), F (below the horizon).
HeliacalEventKind: MorningFirst, EveningLast, EveningFirst, MorningLast.
21. moira.vedic — Vedic Astrology Surface
moira.vedic collects every Vedic-domain subsystem into a single coherent import surface. It inherits the full moira.essentials surface and adds: sidereal positioning, nakshatras, panchanga, source-scoped Pancha Pakshi, all 16 vargas, Vedic dignities, Vimshottari and alternate dasha systems (Ashtottari, Yogini), Jaimini karakas, Ashtakavarga, and Shadbala.
It does not include the Western classical surface (Arabic lots, Firdaria, Zodiacal Releasing, Huber, etc.). For that, use moira.classical. For the complete surface, use moira.facade.
from moira.vedic import *
moment = datetime(1985, 3, 21, 6, 0, tzinfo=timezone.utc)
m = Moira()
chart = m.chart(moment)
# Sidereal and nakshatra positions
ayan = ayanamsa(chart.jd_ut, Ayanamsa.LAHIRI)
naks = all_nakshatras_at(chart.longitudes(), chart.jd_ut)
# Panchanga
pg = panchanga_at(
chart.planets['Sun'].longitude,
chart.planets['Moon'].longitude,
chart.jd_ut,
)
# Source-scoped nominal Pancha Pakshi; no datetime, location, or default profile
pp = pancha_pakshi_schedule(
'agastya_madras_1879_akshara_fixed_clock',
paksha=PanchaPakshiPaksha.PURVA,
half=PanchaPakshiHalf.DAY,
weekday=PanchaPakshiWeekday.SUNDAY,
)
# Standalone source-mapped lunar-half inference; no location or schedule routing
pp_paksha = m.pancha_pakshi_astronomical_paksha(
'agastya_madras_1879_akshara_fixed_clock',
datetime(1985, 3, 21, 6, 0, tzinfo=timezone.utc),
)
# Modern local-solar context; caller still supplies the source-label paksha
pp_context = m.pancha_pakshi_local_solar_context(
'agastya_madras_1879_akshara_fixed_clock',
datetime(1985, 3, 21, 6, 0, tzinfo=timezone.utc),
28.6,
77.2,
paksha=PanchaPakshiPaksha.PURVA,
)
# Explicit modern fixed-clock materialization; no current-cell selection
pp_fixed = m.pancha_pakshi_fixed_clock_materialization(
'agastya_madras_1879_akshara_fixed_clock',
datetime(1985, 3, 21, 6, 0, tzinfo=timezone.utc),
28.6,
77.2,
paksha=PanchaPakshiPaksha.PURVA,
)
# Separate solar-half-first current-cell selection; paksha remains explicit
pp_current = m.pancha_pakshi_fixed_clock_current_cell(
'agastya_madras_1879_akshara_fixed_clock',
datetime(1985, 3, 21, 6, 0, tzinfo=timezone.utc),
28.6,
77.2,
paksha=PanchaPakshiPaksha.PURVA,
)
# Vedic dignities
d = vedic_dignity('Mars', chart.longitudes()['Mars'])
# Vimshottari dasha
periods = vimshottari(
chart.planets['Moon'].longitude,
chart.jd_ut,
levels=2,
)
# Shadbala convenience method on the facade
houses = m.houses(moment, latitude=28.6, longitude=77.2)
strength = m.shadbala_for_chart(chart, houses)
Sidereal, Ayanamsa, and Nakshatras
from moira.vedic import (
UserDefinedAyanamsa, NakshatraPosition,
nakshatra_of, all_nakshatras_at,
# ayanamsa, tropical_to_sidereal, sidereal_to_tropical already in essentials
)
| Function | Signature | Description |
|---|---|---|
nakshatra_of(tropical_longitude, jd, ayanamsa_system=Ayanamsa.LAHIRI) | → NakshatraPosition | Nakshatra position for a tropical ecliptic longitude |
all_nakshatras_at(positions: dict[str, float], jd, ayanamsa_system=Ayanamsa.LAHIRI) | → dict[str, NakshatraPosition] | Nakshatra positions for all bodies in a chart |
NakshatraPosition fields
| Field | Type | Description |
|---|---|---|
nakshatra | str | Nakshatra name |
nakshatra_index | int | 0–26 |
nakshatra_lord | str | Dasha lord of this nakshatra |
pada | int | 1–4 |
degrees_in | float | Degrees into this nakshatra (0–13.333°) |
sidereal_lon | float | Sidereal longitude used for the calculation |
UserDefinedAyanamsa — define a custom ayanamsa by specifying an offset in degrees or a reference epoch.
Pancha Pakshi (Named Source-Scoped Profiles)
from moira.vedic import (
available_pancha_pakshi_profiles,
pancha_pakshi_profile_info,
pancha_pakshi_identity_from_initial_vowel,
pancha_pakshi_schedule,
pancha_pakshi_first_eat_bird_mapping,
pancha_pakshi_astronomical_paksha_at,
pancha_pakshi_nakshatra_bird_mapping,
pancha_pakshi_natal_moon_identity_at,
pancha_pakshi_padu_bird_mapping,
pancha_pakshi_sookshma_temporal_selection,
pancha_pakshi_schedule_sookshma_temporal_selection,
pancha_pakshi_civil_time_sookshma_selection_at,
pancha_pakshi_local_solar_context_at,
pancha_pakshi_fixed_clock_materialization_at,
pancha_pakshi_fixed_clock_current_cell_at,
pancha_pakshi_solar_proportional_materialization_at,
pancha_pakshi_solar_proportional_current_cell_at,
pancha_pakshi_directed_relationship,
PanchaPakshiCurrentCellSelectionStatus,
PanchaPakshiFixedClockCell,
PanchaPakshiFixedClockCurrentCellSelection,
PanchaPakshiFixedClockCurrentCellSelectionPolicy,
PanchaPakshiFixedClockMaterialization,
PanchaPakshiFixedClockMaterializationPolicy,
PanchaPakshiLocalSolarContext,
PanchaPakshiLocalSolarContextPolicy,
PanchaPakshiMaterializedCellRelation,
PanchaPakshiSolarProportionalCell,
PanchaPakshiSolarProportionalCurrentCellSelection,
PanchaPakshiSolarProportionalCurrentCellSelectionPolicy,
PanchaPakshiSolarProportionalMaterialization,
PanchaPakshiSolarProportionalMaterializationPolicy,
PanchaPakshiSolarBoundaryRelation,
PanchaPakshiAstronomicalPaksha,
PanchaPakshiAstronomicalPakshaInference,
PanchaPakshiAstronomicalPakshaInferencePolicy,
PanchaPakshiNakshatraBirdMapping,
PanchaPakshiNatalMoonIdentity,
PanchaPakshiNatalMoonIdentityPolicy,
PanchaPakshiFirstEatBirdMapping,
PanchaPakshiPaduBirdMapping,
PanchaPakshiSookshmaInterval,
PanchaPakshiSookshmaSelection,
PanchaPakshiSookshmaSelectorPolicy,
PanchaPakshiSookshmaSelectorPolicyId,
PanchaPakshiSookshmaTimingPolicyId,
PanchaPakshiScheduleSookshmaCompositionPolicy,
PanchaPakshiScheduleSookshmaSelection,
PanchaPakshiCivilTimeSookshmaRoutingPolicy,
PanchaPakshiCivilTimeSookshmaSelection,
PanchaPakshiBird,
PanchaPakshiPaksha,
PanchaPakshiHalf,
PanchaPakshiWeekday,
)
| Function | Return | Description |
|---|---|---|
available_pancha_pakshi_profiles() | tuple[PanchaPakshiProfileDescriptor, ...] | List public named profiles without selecting a default |
pancha_pakshi_uromarisi_constitution_status() | PanchaPakshiUromarisiConstitutionStatus | Return immutable SCP closure and admission metadata without exposing private historical/network research |
pancha_pakshi_profile_info(profile_id) | PanchaPakshiProfileInfo | Inspect admission, capabilities, source, locators, conflicts, and omissions |
pancha_pakshi_identity_from_initial_vowel(profile_id, initial_vowel) | PanchaPakshiInitialVowelIdentity | Resolve one explicitly listed aksara/query-or-name initial; not natal Moon identity |
pancha_pakshi_schedule(profile_id, *, paksha, half, weekday) | PanchaPakshiSchedule | Materialize one exact nominal fixed-clock schedule from explicit source labels |
pancha_pakshi_first_eat_bird_mapping(profile_id, *, profile_paksha, half, weekday) | PanchaPakshiFirstEatBirdMapping | Return one named generator's directly attested first-samam EAT seed without materializing its schedule or assigning whole-day/authority semantics |
pancha_pakshi_astronomical_paksha_at(profile_id, jd_ut1, *, reader=None) | PanchaPakshiAstronomicalPakshaInference | Classify apparent geocentric Moon-minus-Sun elongation on one reader-bound TT and map Shukla/waxing to Purva or Krishna/waning to Amara for the named profile; no location or schedule routing |
pancha_pakshi_nakshatra_bird_mapping(profile_id, *, profile_paksha, nakshatra_index) | PanchaPakshiNakshatraBirdMapping | Return one directly attested source-table cell without computing or claiming a natal Moon |
pancha_pakshi_natal_moon_identity_at(profile_id, jd_ut1, *, reader=None) | PanchaPakshiNatalMoonIdentity | Apply the named Bogamuni table through the fixed modern apparent-geocentric, Lahiri-true, equal-27-sector natal-Moon policy while exposing every intermediate and source mapping |
pancha_pakshi_padu_bird_mapping(profile_id, *, profile_paksha, weekday) | PanchaPakshiPaduBirdMapping | Return one directly attested Padu bird from the explicit Paksha-by-weekday table; no day/night, instant, schedule, or activity conversion |
pancha_pakshi_sookshma_temporal_selection(profile_id, *, policy_id, parent_activity, elapsed_nazhigai) | PanchaPakshiSookshmaSelection | Select one exact half-open interval within a six-nazhigai samam under a mandatory weighted or equal-fifths policy; no default, clock, astronomy, schedule, Uromarisi outcome, or prognostic interpretation |
pancha_pakshi_schedule_sookshma_temporal_selection(schedule_profile_id, selector_profile_id, *, profile_paksha, half, weekday, samam_index, subject_bird, selector_policy_id, elapsed_nazhigai) | PanchaPakshiScheduleSookshmaSelection | Compose one explicit nominal schedule samam and subject bird with one explicit selector policy and exact elapsed fraction; no clock or outcome binding |
pancha_pakshi_civil_time_sookshma_selection_at(schedule_profile_id, selector_profile_id, jd_ut1, latitude, longitude, *, profile_paksha, subject_bird, timing_policy_id, selector_policy_id, reader=None) | PanchaPakshiCivilTimeSookshmaSelection | Route one instant through an explicit fixed-clock or solar-proportional materialization, derive samam and exact elapsed fraction, and invoke Stage 2N without policy fallback or outcome interpretation |
pancha_pakshi_local_solar_context_at(profile_id, jd_ut1, latitude, longitude, *, paksha, reader=None) | PanchaPakshiLocalSolarContext | Resolve topocentric local-solar half and local-mean-solar weekday from UT1, retain caller-supplied paksha, and select the existing nominal schedule |
pancha_pakshi_fixed_clock_materialization_at(profile_id, jd_ut1, latitude, longitude, *, paksha, reader=None) | PanchaPakshiFixedClockMaterialization | Anchor the selected nominal schedule at governing sunrise or sunset, apply its exact offsets on reader-bound TT, project endpoints to UT1, and report unclipped solar-boundary topology without selecting a current cell |
pancha_pakshi_fixed_clock_current_cell_at(profile_id, jd_ut1, latitude, longitude, *, paksha, reader=None) | PanchaPakshiFixedClockCurrentCellSelection | Resolve the governing solar half first, then return its unique half-open fixed-clock cell or the explicit unmaterialized long-half-tail status |
pancha_pakshi_solar_proportional_materialization_at(profile_id, jd_ut1, latitude, longitude, *, paksha, reader=None) | PanchaPakshiSolarProportionalMaterialization | Map every exact nominal offset fraction independently across the actual governing solar half on reader-bound TT, publish TT and UT1 endpoints, and return the complete 25-cell half-open schedule without current-cell selection |
pancha_pakshi_solar_proportional_current_cell_at(profile_id, jd_ut1, latitude, longitude, *, paksha, reader=None) | PanchaPakshiSolarProportionalCurrentCellSelection | Resolve the governing solar half first, materialize its complete Stage 2D proportional schedule, and return the unique cell containing the requested reader-bound TT instant under exact half-open ownership |
pancha_pakshi_directed_relationship(profile_id, subject, target) | PanchaPakshiDirectedRelationship | Return one stored ordered non-self relation without reciprocal inference |
PanchaPakshiAstronomicalPakshaInferencePolicy is immutable and has no
caller-configurable switches. Its only policy ID is
apparent_geocentric_moon_sun_longitude_paksha_half_open_v1: UT1 is converted
once to reader-bound TT, and apparent geocentric Sun and Moon longitudes are
evaluated in the true ecliptic of date on that shared TT coordinate with
aberration, gravitational deflection, and nutation enabled. The normalized
Moon - Sun longitude occupies [0, 360) degrees. Exact half-open ownership is
[0, 180) Shukla and [180, 360) Krishna with 0.0-degree tolerance and no
snapping. A common ayanamsa is not applied because it cancels from this
difference.
The named profile's source-attested mapping is Shukla/waxing to Purva at IA
leaf n16, and Krishna/waning to Amara at n26. That machine-assisted visual
reading remains source-scoped with explicit uncertainty and no human-review
dependency; it is not an independent-witness or universal-canon claim.
| Stage 2F vessel | Public contract |
|---|---|
PanchaPakshiAstronomicalPaksha | Finite astronomical phase-half enum: shukla or krishna; it remains distinct from the profile-owned purva/amara enum |
PanchaPakshiAstronomicalPakshaInferencePolicy | Origin, frame, corrections, time scales, elongation definition, exact half-open boundary ownership, source mapping basis and locators, plus explicit non-performance of schedule selection, materialization, and natal identity |
PanchaPakshiAstronomicalPakshaInference | Profile ID, requested UT1 and TT, Sun/Moon longitudes, normalized elongation, astronomical and profile labels, exactly one direct mapping locator, immutable policy, and route-specific provenance |
The inference accepts no location or caller-supplied paksha. It never selects or materializes a schedule, identifies a current cell, feeds the result into another operation, or infers natal identity.
PanchaPakshiNakshatraBirdMapping is the pure Stage 2G source-table vessel. The
named bogamuni_chennai_2024_nakshatra_natal_identity profile contains exactly
54 cells: two profile Paksha labels by 27 named nakshatras. Purva mappings cite
the rendered original at IA leaf n52; Amara mappings cite the complete verse
at n64. The adjacent Amara commentary duplicates Shravana and omits Revati,
so assembly_policy="verse_precedence_for_nakshatra_partition" preserves that
commentary as rejected conflict evidence and does not repair or blend it. The
source-table vessel states
source_table_semantics="nakshatra_bird_table_not_explicitly_natal_moon".
The strict transport equivalent is
POST /v1/pancha-pakshi/mappings/nakshatra-bird; it accepts only explicit
profile, source Paksha, and zero-based nakshatra index.
PanchaPakshiNatalMoonIdentityPolicy is fixed, immutable, and has policy ID
bogamuni_2024_apparent_lahiri_natal_moon_identity_v1. One UT1 instant becomes
one reader-bound TT epoch. Apparent geocentric Sun and Moon longitudes in the
true ecliptic of date determine the half-open Shukla/Krishna phase; the source
binding at Bogamuni leaf n167 maps that half to Purva or Amara. The same TT
epoch supplies Lahiri true ayanamsa and the sidereal Moon, which is classified
into 27 equal half-open 40/3-degree sectors. Exact internal boundaries belong
to the following nakshatra, with maximum-one-ULP-below recovery only for the
binary representation of an exact mathematical boundary.
The policy's public token is exactly ayanamsa_system="Lahiri", matching
Ayanamsa.LAHIRI and the strict sidereal transport vocabulary.
The policy explicitly reports
composition_status="modern_moira_policy_not_source_claim" and
ayanamsa_status="fixed_modern_moira_policy_not_source_attested": the source
attests phase labels and nakshatra birds, not birth-Moon application, Lahiri, or
the equal-sector computational partition. The result exposes requested UT1/TT,
Sun and tropical Moon, elongation, astronomical and profile Paksha, phase
locator, ayanamsa, sidereal Moon, nakshatra index/name/degrees, nested bird
mapping and locator, full policy, and provenance. It performs no schedule
selection, materialization, current-cell selection, scoring, or forecast.
| Stage 2G vessel | Public contract |
|---|---|
PanchaPakshiNakshatraBirdMapping | Pure source-table Paksha, nakshatra index/name, bird, direct-attestation status, declared verse precedence, one mapping locator, and profile provenance; no epoch or natal claim |
PanchaPakshiNatalMoonIdentityPolicy | Fixed astronomical origin/frame/corrections/time scales, half-open phase and nakshatra ownership, source phase binding, Lahiri-true modern composition, verse precedence, and explicit non-performance fields |
PanchaPakshiNatalMoonIdentity | All astronomical and sidereal intermediates, phase mapping, nakshatra placement, nested source-table mapping, immutable policy, and route-specific provenance |
PanchaPakshiPaduBirdMapping is the pure Stage 2H source-table vessel. The
separate bogamuni_chennai_2024_padu_bird_mapping profile contains exactly
fourteen cells: two explicit source Paksha labels by seven weekdays, with no
day/night axis. Purva cells cite the governing n52 stanza; Amara cells cite
n60; every result also cites the repeated combined table at n157 and its
restating commentary at n158. Its assembly policy is
paksha_stanzas_govern_repeated_combined_table_confirms, and its source
semantics are
profile_paksha_weekday_death_or_inoperative_bird_not_schedule_rule_activity.
The lookup accepts no instant, location, half, schedule, natal, condition,
score, or forecast input. It neither converts Padu to RULE nor relabels
first_eat_bird, authority day, Adhikara, or Bharana.
| Stage 2H vessel | Public contract |
|---|---|
PanchaPakshiPaduBirdMapping | Explicit profile Paksha and weekday, one directly attested Padu bird, three canonical locators, stanza-precedence assembly policy, source-table semantics, and profile provenance; no temporal or schedule claim |
PanchaPakshiFirstEatBirdMapping is the pure Stage 2I source-table vessel on
the unchanged 1879 profile. Its 28 possible cells cover two explicit profile
Pakshas, two day/night halves, and seven weekdays. Each result identifies the
canonical generator, its first-samam EAT bird, direct-attestation status, fixed
source semantics, complete generator locator tuple, and profile provenance.
It accepts no instant, location, inferred Paksha, schedule-materialization,
Padu/authority/Adhikara/Bharana, natal, condition, score, or forecast input.
| Stage 2I vessel | Public contract |
|---|---|
PanchaPakshiFirstEatBirdMapping | Explicit profile, Paksha, half, and weekday; canonical generator ID; one directly attested first_eat_bird; full generator locator tuple and provenance; no temporal, whole-day, authority, or materialized-schedule claim |
Stage 2K adds the separate
bogamuni_chennai_2024_sookshma_temporal_selector profile. Its sole capability
is sookshma_temporal_selection; default_selection_allowed remains false.
Every call names one PanchaPakshiSookshmaSelectorPolicyId, a parent activity,
and an exact Fraction offset in [0, 6). The weighted policy rotates the
source-attested activity-duration vector from the parent activity. The
equal-fifths policy returns five exact 6/5-nazhigai ordinal cells with
activity=None, because the source does not attest a subactivity assignment.
Both policies use exact [start, end) ownership and return their five cells,
the unique selected ordinal and interval, source locators, and provenance.
They perform no datetime, astronomy, schedule, Uromarisi outcome, condition,
score, electional, or forecast composition and have no human-review
dependency.
| Stage 2K vessel | Public contract |
|---|---|
PanchaPakshiSookshmaSelectorPolicy | Mandatory policy ID, exact container and duration doctrine, half-open ownership, explicit no-default/no-Uromarisi-composition statuses, and two source locators |
PanchaPakshiSookshmaInterval | Ordinal, optional source-attested activity, and exact rational start, end, and duration |
PanchaPakshiSookshmaSelection | Explicit profile, policy, parent activity, exact elapsed offset, all five intervals, unique selected interval, source locators, and provenance; no outcome semantics |
PanchaPakshiLocalSolarContextPolicy is fixed and inspectable:
policy_id="local_solar_day_explicit_paksha_v1", caller-supplied source-label
paksha, topocentric sunrise-to-next-sunrise day, -0.833-degree solar-event
altitude, fixed 0 m observer elevation, unrefracted altitude signal with
conventional standard refraction and solar semidiameter incorporated in the
threshold, sunrise/sunset half, local-mean-solar weekday at governing sunrise,
and offset_materialization_status="not_performed". The result exposes the
requested UT1 JD, sunrise/sunset/next-sunrise UT1 JDs, location, paksha, half,
weekday, policy, selected nominal schedule, and provenance. Its provenance
routing status is
local_solar_half_and_weekday_performed_paksha_caller_supplied.
PanchaPakshiFixedClockMaterializationPolicy admits only
policy_id="fixed_24_minute_nazhigai_from_local_solar_half_start_v1". Day
anchors at governing topocentric sunrise and night at governing topocentric
sunset. One nazhigai is exactly 1440 SI seconds; the fixed 30-nazhigai half is
43200 seconds. Exact offsets are added on reader-bound TT, endpoints are
projected to UT1, intervals are half-open, and the fixed end is never clipped
or stretched to the solar end. The result reports
fixed_end_jd_tt_minus_solar_end_jd_tt with 0.0001 s numerical coalescence,
per-cell solar-half relations, and routing status
fixed_clock_materialization_performed_paksha_caller_supplied_no_current_cell.
It performs neither current-cell selection nor solar-proportional scaling.
PanchaPakshiFixedClockCurrentCellSelectionPolicy admits only
policy_id="fixed_clock_current_cell_half_open_solar_precedence_v1" and binds
the Stage 2B materialization policy. The governing solar half is resolved
before selection; membership uses reader-bound TT, exact half-open ownership,
and 0.0 s tolerance. Shared endpoints belong to the following cell. Cells
from a prior short half are ineligible after its solar boundary, while a long
half that outlasts the fixed span returns
selection_status="unmaterialized_solar_half_tail" and current_cell=None.
The selector performs no clipping, wrapping, repeating, proportional scaling,
or astronomical paksha inference. Its other finite status is selected.
PanchaPakshiSolarProportionalMaterializationPolicy is the separate Stage 2D
policy and admits only
policy_id="solar_proportional_nominal_offsets_over_governing_half_tt_v1".
Each exact source nominal offset is divided by the complete 30-nazhigai nominal
span, and every resulting rational endpoint fraction is mapped independently
as anchor plus that fraction of the actual governing local-solar half on
reader-bound TT. Interior endpoints are projected to UT1 through the same
reader; the outer endpoints close exactly on the TT and UT1 anchor and
governing solar-half end. The result contains exactly 25 contiguous, positive,
half-open cells and performs no clipping, wrapping, repetition, fixed
1,440-second nazhigai conversion, current-cell selection, or astronomical
paksha inference.
| Stage 2D vessel | Public contract |
|---|---|
PanchaPakshiSolarProportionalMaterialization | Stage 2A context, immutable policy, TT/UT1 anchor and governing-half-end fields, solar_half_duration_seconds_tt, 25 cells, and profile-owned provenance |
PanchaPakshiSolarProportionalMaterializationPolicy | Explicit caller-supplied-paksha, topocentric solar-half, reader-bound-TT mapping, UT1 publication, exact endpoint-closure, and half-open ownership doctrine, with fixed-clock seconds and current-cell selection marked not used or not performed |
PanchaPakshiSolarProportionalCell | Ordered schedule index, unchanged nominal cell, exact start_offset_fraction, end_offset_fraction, and span_fraction, TT/UT1 endpoints, and TT duration |
PanchaPakshiSolarProportionalCurrentCellSelectionPolicy admits only
policy_id="solar_proportional_current_cell_half_open_solar_precedence_v1"
and binds the Stage 2D materialization policy. Stage 2A resolves the governing
solar half before selection; the requested instant is converted to reader-bound
TT once; and membership is exactly
start_jd_tt <= requested_jd_tt < end_jd_tt with 0.0 s tolerance. The anchor
belongs to cell zero, shared endpoints belong to the following cell, and exact
sunrise or sunset belongs to the new half. Complete Stage 2D coverage makes
selection_status="selected" and one non-null materialization member the only
lawful result. Zero or multiple matches fail closed. The selector admits no
tail, fallback, fixed-clock mixing, clipping, wrapping, borrowing, astronomical
paksha inference, or natal identity.
| Stage 2E vessel | Public contract |
|---|---|
PanchaPakshiSolarProportionalCurrentCellSelection | Complete governing Stage 2D materialization, immutable selection policy, requested TT witness, selected-only status, one non-null materialization member, and route-specific provenance |
PanchaPakshiSolarProportionalCurrentCellSelectionPolicy | Stage 2D policy binding, caller-supplied paksha, reader-bound-TT selection, exact half-open ownership, solar-half-first precedence, zero tolerance, complete-coverage requirement, exactly-one-match failure policy, and explicit non-use of fixed-clock mixing or paksha inference |
The current agastya_madras_1879_akshara_fixed_clock profile is
source_scoped_public and can never be selected implicitly. It performs no
natal mapping, subdivision, or scoring computation. Its separately admitted
Stage 2F product performs only explicit astronomical paksha inference and
source-label mapping; it does not alter any schedule route. Its Stage 2I
capability exposes only one named generator's first-samam EAT seed and performs
no time routing, schedule materialization, or authority-role inference. The modern
local_solar_day_explicit_paksha_v1 policy derives only topocentric
sunrise/sunset context, day/night half, and local-mean-solar weekday while the
paksha remains explicit. It returns the nominal schedule, not a current cell or
clock-time interval. Stage 2B separately materializes fixed 1,440-second
nazhigai offsets, and Stage 2C selects a current cell only from that fixed-clock
materialization. Stage 2D is a distinct explicit modern Moira policy that maps
the exact nominal fractions across the actual solar half. Stage 2E separately
selects the unique current cell from that complete materialization. The named
1879 witness attests the nominal schedule, rational offsets, bird/activity
assignments, chronology, locators, and the waxing/Purva and waning/Amara
mapping; it does not attest Moira's exact numerical phase boundaries or
proportional sunrise-to-sunset timing. Every result carries immutable
profile-owned provenance and declared omissions. See the
governing admission standard for the
source and evidence boundary.
The separate bogamuni_chennai_2024_nakshatra_natal_identity profile is also
source_scoped_public and can never be selected implicitly. It admits only the
pure 54-cell nakshatra_bird_mapping product and its explicitly modern
natal_identity composition. It supplies no aksara identity, operating
schedule, relationship, materialization, current cell, authority bird,
subdivision, condition, score, or window search. It does not alter or extend
the 1879 profile.
The separate bogamuni_chennai_2024_padu_bird_mapping profile is likewise
source_scoped_public, no-default, and Padu-only. It admits exactly one
Paksha-by-weekday lookup capability and supplies no day/night axis, identity,
schedule, materialization, current cell, authority-bird alias, condition,
score, or forecast. The primary evidence distinguishes eating bird and
authority day rather than attesting an Adhikara Pakshi table; Bharana remains
secondary-only terminology. Neither term aliases the public Padu vessel.
The Moira facade supplies these ten kernel-free operations:
pancha_pakshi_profiles, pancha_pakshi_profile_info,
pancha_pakshi_identity_from_initial_vowel,
pancha_pakshi_schedule, pancha_pakshi_directed_relationship,
pancha_pakshi_nakshatra_bird_mapping, and
pancha_pakshi_padu_bird_mapping,
pancha_pakshi_first_eat_bird_mapping, and
pancha_pakshi_sookshma_temporal_selection, and
pancha_pakshi_schedule_sookshma_temporal_selection. It
additionally supplies the kernel-backed
pancha_pakshi_astronomical_paksha(profile_id, dt),
pancha_pakshi_natal_moon_identity(profile_id, dt),
pancha_pakshi_local_solar_context(profile_id, dt, latitude, longitude, *, paksha) and pancha_pakshi_fixed_clock_materialization(profile_id, dt, latitude, longitude, *, paksha), plus the
pancha_pakshi_fixed_clock_current_cell(profile_id, dt, latitude, longitude, *, paksha) and
pancha_pakshi_solar_proportional_materialization(profile_id, dt, latitude, longitude, *, paksha) and
pancha_pakshi_solar_proportional_current_cell(profile_id, dt, latitude, longitude, *, paksha) and
pancha_pakshi_civil_time_sookshma_selection(schedule_profile_id, selector_profile_id, dt, latitude, longitude, *, profile_paksha, subject_bird, timing_policy_id, selector_policy_id) adapters for aware datetimes. The low-level
engine functions accept UT1 JD, while the facade preserves UTC civil anchoring
before the UT1 conversion. Fixed-clock and solar-proportional offset arithmetic
use reader-bound TT under their distinct policies, with both TT and projected
UT1 endpoints returned. The Stage 2D and Stage 2E engine functions, result,
policy, and cell vessels are first-class exports from moira, moira.facade,
and moira.vedic; the Stage 2F function, enum, result, and policy vessels are
exported through those same surfaces, as are the Stage 2G mapping, natal result,
policy, and functions. The astronomical-paksha and natal-Moon facades accept an
aware datetime but no location or caller-supplied paksha. The former's inferred
label is never ambiently routed into the six location-bearing operations, and
the latter returns an identity only without routing into any schedule family.
The Stage 2H function, vessel, and facade lookup are also exported through all
three Python surfaces and perform no clock or kernel access.
The Stage 2I function, vessel, and facade lookup are likewise exported through
all three surfaces and return only the named generator's first-samam EAT seed.
The Stage 2K selector function, policy ID, policy, interval, result vessel, and
facade method are exported through the same surfaces. The method requires an
explicit policy and exact elapsed Fraction; it performs no clock, astronomy,
schedule, Uromarisi outcome, condition, score, or forecast composition.
The separate Stage 2N method requires both profile IDs, explicit schedule
axes, samam, subject bird, selector policy, and exact elapsed Fraction. It
derives the subject bird's parent activity from the named schedule samam under
the modern explicit_schedule_samam_subject_bird_sookshma_v1 policy. It still
performs no clock, astronomy, Uromarisi outcome, condition, score, or forecast
operation. The matching strict route is
POST /v1/pancha-pakshi/sookshma/schedule-select.
The Stage 2O method additionally requires an aware datetime, location, source
Paksha, subject bird, explicit timing policy, and explicit selector policy. It
derives samam and elapsed nazhigai from the selected materialized reader-bound
TT interval under civil_time_materialized_samam_to_stage2n_v1. A fixed-clock
long-half tail remains an explicit null composition and never falls back to
solar-proportional timing. The matching strict route is
POST /v1/pancha-pakshi/sookshma/civil-time-select.
Panchanga
from moira.vedic import (
panchanga_at, sankranti_at, tithi_condition_profile, panchanga_profile,
PanchangaResult, SankrantiResult, TithiConditionProfile, PanchangaProfile,
TithiPaksha, YogaClass, KaranaType, VaraLordType, PanchangaPolicy,
TITHI_NAMES, YOGA_NAMES, KARANA_NAMES, VARA_LORDS, VARA_NAMES, RASHI_NAMES,
)
| Function | Signature | Description |
|---|---|---|
panchanga_at(sun_tropical_lon, moon_tropical_lon, jd, ayanamsa_system='Lahiri', policy=None) | → PanchangaResult | Five Panchanga elements at a given JD |
sankranti_at(jd_start, jd_end, reader=None) | → SankrantiResult | Solar ingress into each rashi in a date range |
tithi_condition_profile(result) | → TithiConditionProfile | Tithi quality assessment |
panchanga_profile(result) | → PanchangaProfile | Aggregate Panchanga quality profile |
Tithi and Karana share the normalized tropical Moon - Sun phase coordinate.
The common ayanamsa would cancel from that difference, so Moira does not derive
these boundaries by subtracting two separately rounded sidereal longitudes.
This preserves exact conjunction, opposition, tithi, and half-tithi ownership;
the Panchanga result still publishes the selected sidereal longitudes for the
products that use them.
PanchangaResult fields
| Field | Type | Description |
|---|---|---|
tithi | int | Lunar day (1–30) |
tithi_name | str | Name from TITHI_NAMES |
paksha | TithiPaksha | Shukla (waxing) or Krishna (waning) |
yoga | int | Yoga index (0–26) |
yoga_name | str | Name from YOGA_NAMES |
yoga_class | YogaClass | Auspicious / Inauspicious / Neutral |
karana | int | Karana index |
karana_name | str | Name from KARANA_NAMES |
karana_type | KaranaType | Fixed or Movable |
vara | int | Weekday (0 = Sunday) |
vara_lord | VaraLordType | Planetary ruler of the day |
Vedic Dignities
from moira.vedic import (
vedic_dignity, planetary_relationships, dignity_condition_profile, chart_dignity_profile,
VedicDignityResult, PlanetaryRelationship, VedicDignityPolicy,
DignityConditionProfile, ChartDignityProfile,
VedicDignityRank, CompoundRelationship, DignityTier,
)
| Function | Signature | Description |
|---|---|---|
vedic_dignity(planet, longitude, policy=None) | → VedicDignityResult | Essential Vedic dignity for a planet at a longitude |
planetary_relationships(planet, jd_ut, policy=None) | → PlanetaryRelationship | Natural + temporary + compound friendship |
dignity_condition_profile(planet, chart) | → DignityConditionProfile | Dignity assessment with tier classification |
chart_dignity_profile(chart) | → ChartDignityProfile | Full chart-wide dignity analysis |
Dignity constants: EXALTATION_SIGN, EXALTATION_DEGREE, DEBILITATION_SIGN, MULATRIKONA_SIGN, OWN_SIGNS, NATURAL_FRIENDS, NATURAL_NEUTRALS, NATURAL_ENEMIES.
Varga — Divisional Charts
from moira.vedic import (
VargaPoint, calculate_varga,
navamsa, saptamsa, dashamansa, dwadashamsa, trimshamsa,
hora, chaturthamsha, shashthamsha, ashtamsha, shodashamsha,
vimshamsha, chaturvimshamsha, saptavimshamsha,
khavedamsha, akshavedamsha, shashtiamsha,
)
calculate_varga(longitude, divisor) → VargaPoint — low-level entry point for any divisor.
Named functions follow the pattern navamsa(longitude) → VargaPoint:
| Function | Division | Traditional name |
|---|---|---|
hora | D-2 | Hora chart |
saptamsa | D-7 | Children / fertility |
navamsa | D-9 | Marriage / dharma |
dashamansa | D-10 | Career / profession |
dwadashamsa | D-12 | Ancestors / parents |
chaturthamsha | D-4 | Property |
shashthamsha | D-6 | Enemies / health |
ashtamsha | D-8 | Longevity |
shodashamsha | D-16 | Vehicles, comforts |
vimshamsha | D-20 | Spirituality |
chaturvimshamsha | D-24 | Education, learning |
saptavimshamsha | D-27 | Strength |
trimshamsa | D-30 | Evils, illness |
khavedamsha | D-40 | Auspicious/inauspicious effects |
akshavedamsha | D-45 | All matters |
shashtiamsha | D-60 | Past life karma |
Vimshottari Dasha
from moira.vedic import (
vimshottari, current_dasha, dasha_balance, dasha_active_line,
dasha_condition_profile, dasha_sequence_profile, dasha_lord_pair,
DashaPeriod, DashaActiveLine, DashaConditionProfile,
DashaSequenceProfile, DashaLordPair,
VimshottariComputationPolicy, DEFAULT_VIMSHOTTARI_POLICY,
VIMSHOTTARI_YEARS, VIMSHOTTARI_SEQUENCE, VIMSHOTTARI_TOTAL,
)
| Function | Signature | Description |
|---|---|---|
vimshottari(moon_tropical_lon, natal_jd, levels=2, ayanamsa_system=None, *, year_basis=None, policy=None) | → list[DashaPeriod] | Full generated sequence from birth |
current_dasha(moon_tropical_lon, natal_jd, current_jd, ayanamsa_system=None, *, year_basis=None, levels=5, policy=None) | → list[DashaPeriod] | Active period at each requested level |
dasha_balance(moon_tropical_lon, natal_jd, ayanamsa_system=None, *, year_basis=None, policy=None) | → tuple[str, float] | (lord, years_remaining) at birth |
dasha_active_line(active_periods) | → DashaActiveLine | Named active chain from current_dasha(...) output |
dasha_condition_profile(period) | → DashaConditionProfile | Condition assessment for one DashaPeriod |
dasha_sequence_profile(periods) | → DashaSequenceProfile | Aggregate profile for vimshottari(...) output |
dasha_lord_pair(line) | → DashaLordPair | Mahadasha and Antardasha lords from an active line |
VIMSHOTTARI_YEARS — dict of dasha lord → years in the 120-year cycle.
VIMSHOTTARI_SEQUENCE — canonical lord sequence (Ketu, Venus, Sun, Moon, …).
Alternate Dasha Systems — Ashtottari and Yogini
from moira.vedic import (
ashtottari, yogini_dasha,
AlternateDashaPeriod, AshtottariPolicy, YoginiPolicy,
AlternatePeriodProfile, AlternateDashaSequenceProfile,
ASHTOTTARI_YEARS, ASHTOTTARI_SEQUENCE, ASHTOTTARI_TOTAL,
YOGINI_YEARS, YOGINI_SEQUENCE, YOGINI_PLANETS, YOGINI_TOTAL,
)
| Function | Signature | Description |
|---|---|---|
ashtottari(moon_lon, birth_jd, policy=None) | → list[AlternateDashaPeriod] | 108-year Ashtottari sequence |
yogini_dasha(moon_lon, birth_jd, policy=None) | → list[AlternateDashaPeriod] | 36-year Yogini sequence |
AshtottariPolicy and YoginiPolicy control year-basis and sequence parameters.
Jaimini Karakas
from moira.vedic import (
jaimini_karakas, atmakaraka, karaka_condition_profile, jaimini_chart_profile,
JaiminiKarakaResult, KarakaAssignment, KarakaConditionProfile, JaiminiChartProfile,
JaiminiPolicy, KarakaRole, KarakaPlanetType,
KARAKA_NAMES_7, KARAKA_NAMES_8,
)
| Function | Signature | Description |
|---|---|---|
jaimini_karakas(chart_longitudes, policy=None) | → JaiminiKarakaResult | Full 7- or 8-karaka assignment by degree |
atmakaraka(chart_longitudes, policy=None) | → KarakaAssignment | Highest-degree planet (soul significator) |
karaka_condition_profile(chart_longitudes, policy=None) | → KarakaConditionProfile | Dignity condition for each karaka |
jaimini_chart_profile(chart_longitudes, policy=None) | → JaiminiChartProfile | Full chart karaka profile |
JaiminiPolicy controls the 7-karaka vs. 8-karaka scheme and Rahu tie-break behaviour.
Ashtakavarga
from moira.vedic import (
bhinnashtakavarga, ashtakavarga, transit_strength,
sign_strength_profile, ashtakavarga_chart_profile,
BhinnashtakavargaResult, AshtakavargaResult,
SignStrengthProfile, AshtakavargaChartProfile,
AshtakavargaPolicy, RekhaTier, REKHA_TABLES,
)
| Function | Signature | Description |
|---|---|---|
bhinnashtakavarga(planet, chart_longitudes, policy=None) | → BhinnashtakavargaResult | Individual planet's bindus per sign (8-source table) |
ashtakavarga(chart_longitudes, policy=None) | → AshtakavargaResult | Sarvashtakavarga — combined bindus per sign |
transit_strength(planet, transit_lon, natal_chart_longitudes) | → float | Ashtakavarga bindus for a transit position |
sign_strength_profile(chart_longitudes, policy=None) | → SignStrengthProfile | Per-sign bindu strengths with RekhaTier labels |
ashtakavarga_chart_profile(chart_longitudes, policy=None) | → AshtakavargaChartProfile | Full chart Ashtakavarga profile |
Shadbala
from moira.vedic import (
shadbala, sthana_bala, dig_bala, kala_bala, chesta_bala, drig_bala,
hora_lord_at, shadbala_condition_profile, shadbala_chart_profile,
ShadbalaResult, PlanetShadbala, ShadbalaPolicy,
ShadbalaConditionProfile, ShadbalaChartProfile,
SthanaBala, KalaBala, ShadbalaTier,
NAISARGIKA_BALA, REQUIRED_RUPAS,
)
| Function | Signature | Description |
|---|---|---|
shadbala(sidereal_longitudes, planet_speeds, houses, jd, tithi_number, vara_lord, is_day, ayanamsa_system='Lahiri', hora_lord=None, planet_latitudes=None) | → ShadbalaResult | Full six-fold strength for the seven classical planets |
sthana_bala(planet, sidereal_lon, houses, jd, ayanamsa_system='Lahiri') | → SthanaBala | Positional strength components |
dig_bala(planet, sidereal_lon, houses, jd, ayanamsa_system='Lahiri') | → float | Directional strength |
kala_bala(planet, sidereal_lon, sun_sidereal_lon, jd, tithi_number, is_day, vara_lord, planet_speeds, ...) | → KalaBala | Temporal strength components |
chesta_bala(planet, speed, planet_sidereal_lon=None, mandoccha_sidereal_lon=None) | → float | Motional strength |
drig_bala(planet, sidereal_longitudes) | → float | Aspectual strength |
hora_lord_at(birth_jd, sunrise_jd) | → str | Planetary hour ruler from a caller-supplied sunrise |
shadbala_condition_profile(planet_result) | → ShadbalaConditionProfile | Condition assessment for one PlanetShadbala |
shadbala_chart_profile(result) | → ShadbalaChartProfile | Aggregate profile for one ShadbalaResult |
NAISARGIKA_BALA — natural strength constants (Saturn lowest, Sun highest).
REQUIRED_RUPAS — minimum Shadbala rupas required for each planet.
Appendix A — Stability Tiers
| Tier | Meaning | Examples |
|---|---|---|
| Frozen | Signature and semantics will not change without a major version bump | Moira, Chart, Body, HouseSystem, AspectData, HouseCusps, all __all__ members |
| Provisional | None currently designated | — |
Appendix B — Kernel & Reader
from moira.spk_reader import get_reader, set_kernel_path, SpkReader
# Set path globally (persists for the process lifetime):
set_kernel_path("/data/de441.bsp")
# Get the shared singleton reader:
reader = get_reader()
# Or construct a private reader:
reader = get_reader("/data/de441.bsp")
The reader argument accepted by most low-level functions defaults to the
global singleton if None. Pass an explicit reader only when you need
isolation from the global state (e.g., in tests or multi-tenant contexts).
Appendix C — Coverage & Accuracy
| Property | Value |
|---|---|
| Ephemeris | JPL DE441 |
| Date coverage | 13 200 BC → 17 191 AD |
| Coordinate frame | Geocentric ecliptic, tropical (J2000.0 mean equinox) |
| Sidereal option | Any ayanamsa via ayanamsa() / tropical_to_sidereal() |
| ΔT model | Hybrid IERS/Morrison-Stephenson/extrapolation |
| Nutation | IAU 2000A (1365 terms) |
| Obliquity | Laskar 1986 / IAU 2006 combined |
| Topocentric Moon | Parallax-corrected RA/Dec and altitude |
| Fixed stars | Sovereign registry (star_registry.csv + JSON sidecars) |
| Variable stars | 20-star classical catalog with period/epoch/magnitude data |