SWISS_EPHEMERIS_TO_MOIRA_DRAFT - TheDaniel166/moira GitHub Wiki
Status: verified draft, first audit pass; Phase 1–4 row corrections applied 2026-04-04.
This document is a corrected first pass over an AI-generated Swiss Ephemeris translation draft. It is intentionally narrower than the original text. Only mappings verified against the current repository surface are stated as facts here.
Use this as:
- a migration guide for the audited subset
- a correction log for the original draft
- a checklist for the remaining unaudited
pyswissephsurface
Do not treat this file as a complete 420-symbol authoritative map yet.
For inventory purposes, each Swiss symbol should eventually land in one of these buckets:
-
mapped— a clear Moira equivalent exists now -
partial— the intent exists, but the shape is split or not strictly 1:1 -
stdlib— use Python or another non-Moira standard tool instead -
missing— no current Moira equivalent -
unsupported— intentionally outside Moira's design scope
For the 104 symbol rows currently inventoried from the generated draft:
-
mapped: 61 -
partial: 35 -
stdlib: 5 -
missing: 3 -
unsupported: 4
These totals are for the audited rows in this document, not yet for the full
published pyswisseph symbol surface.
The original draft had several structural errors:
- The real constructor is
Moira(kernel_path=...), notMoira(ephe_path=...). - There is no
Moira.planet(...)facade method in the current repo. - There is no public
moira.models.Observerlayer in the current repo. - Rise/set lives in
moira.rise_set, notmoira.riseset. - Ayanamsa constants live in
moira.sidereal.Ayanamsa, notmoira.constants. - Planet result vessels do not expose Swiss-shaped fields like
speed_longitude;PlanetDatausesspeed. -
PlanetData.distanceandSkyPosition.distanceare stored in kilometers, not AU.
Swiss Ephemeris is a flag-driven C API with global mutable state. Moira is a typed Python engine with:
- explicit arguments instead of global setters
- typed result vessels instead of tuples
- facade methods for common workflows
- lower-level engine functions for specialist access
Some migrations are therefore semantic rather than signature-identical.
Swiss global ephemeris path:
import swisseph as swe
swe.set_ephe_path("/path/to/ephe")
swe.set_jpl_file("de441.eph")Moira constructor or reader setup:
from moira import Moira
m = Moira(kernel_path="/path/to/de441.bsp")There is also a lower-level kernel path hook:
from moira.spk_reader import set_kernel_path
set_kernel_path("/path/to/de441.bsp")Swiss global topo observer:
swe.set_topo(lon, lat, alt)Moira does not keep global observer state. Pass observer coordinates per call:
from moira.planets import sky_position_at
sky = sky_position_at(
"Moon",
jd_ut,
observer_lat=lat,
observer_lon=lon,
observer_elev_m=alt,
)There is no swe.close() equivalent.
Verified equivalents in moira.julian:
| Swiss | Moira |
|---|---|
swe.julday(...) |
moira.julian.julian_day(...) |
swe.revjul(...) |
moira.julian.calendar_from_jd(...) |
UTC datetime -> JD
|
moira.julian.jd_from_datetime(dt) |
swe.deltat(...) |
moira.julian.delta_t_from_jd(jd_ut) |
swe.sidtime(...) |
moira.julian.greenwich_mean_sidereal_time(jd_ut) |
| apparent sidereal time | moira.julian.apparent_sidereal_time(...) |
| local sidereal time | moira.julian.local_sidereal_time(...) |
Important difference:
-
delta_t()currently takes a decimal year, not a JD. - The original draft's
utc_to_jd()andjd_to_utc()names do not match the current public surface I have verified inmoira.julian.
The audited low-level engine entry points are in moira.planets:
from moira.planets import planet_at, sky_position_at, all_planets_atLow-level geocentric ecliptic position:
pos = planet_at("Sun", jd_ut)
pos.longitude
pos.latitude
pos.distance # kilometers
pos.speed # degrees/dayTopocentric sky position:
sky = sky_position_at(
"Moon",
jd_ut,
observer_lat=lat,
observer_lon=lon,
observer_elev_m=alt,
)
sky.right_ascension
sky.declination
sky.azimuth
sky.altitude
sky.distance # kilometersFacade-level whole-chart workflow:
from moira import Moira
m = Moira(kernel_path="/path/to/de441.bsp")
chart = m.chart(dt, observer_lat=lat, observer_lon=lon, observer_elev_m=alt)
sun = chart.planets["Sun"]Important corrections to the original draft:
- There is no audited
m.planet(...)facade method. - The nearest stable facade equivalent is usually
m.chart(...)orm.sky_position(...). - The low-level equivalent for Swiss
calc_ut()isplanet_at(...).
Facade:
from moira import Moira
from moira.constants import HouseSystem
m = Moira()
houses = m.houses(dt, latitude=lat, longitude=lon, system=HouseSystem.PLACIDUS)Low-level:
from moira.houses import calculate_houses
houses = calculate_houses(jd_ut, lat, lon, HouseSystem.PLACIDUS)Verified current fact:
-
calculate_houses(...)exists. - The original draft's
houses_from_armcandbody_house_positionclaims are not yet audited in this pass and are intentionally omitted here.
Verified surface is in moira.sidereal:
from moira.sidereal import Ayanamsa, ayanamsa
offset = ayanamsa(jd_ut, Ayanamsa.LAHIRI)Important correction:
-
Ayanamsadoes not live inmoira.constants. - The original draft's
ayanamsa_value(...)name does not match the current audited function; the verified function isayanamsa(...).
Low-level audited surface:
from moira.fixed_stars import fixed_star_at, list_stars, find_stars, star_magnitude
spica = fixed_star_at("Spica", jd_tt)
mag = star_magnitude("Spica")Facade:
from moira import Moira
m = Moira()
spica = m.fixed_star("Spica", dt)Important correction:
- The fixed-star low-level function expects
jd_tt, notjd_ut. - The facade accepts a
datetimeand handles conversion.
The current eclipse engine is class-based, not a flat top-level function set.
Verified surface:
from moira.eclipse import EclipseCalculator
calc = EclipseCalculator()
solar = calc.next_solar_eclipse(jd_start)
lunar = calc.next_lunar_eclipse(jd_start)Facade-level single-moment eclipse evaluation also exists:
from moira import Moira
m = Moira()
data = m.eclipse(dt)Important correction:
- The original draft's top-level imports like
from moira.eclipse import next_solar_eclipseare not verified as current public functions in this repo. - The audited current shape is
EclipseCalculator.next_solar_eclipse(...)andEclipseCalculator.next_lunar_eclipse(...).
Verified surface is in moira.rise_set:
from moira.rise_set import find_phenomena, get_transit, twilight_times
events = find_phenomena("Sun", jd_start, lat, lon)
upper = get_transit("Sun", jd_start, lat, lon, upper=True)
lower = get_transit("Sun", jd_start, lat, lon, upper=False)
twilight = twilight_times(jd_day, lat, lon)Important correction:
- The module is
rise_set, notriseset. - The current API is event-dictionary based, not
next_rise(...)/next_set(...)wrappers.
Verified facade:
from moira import Moira
m = Moira()
nodes = m.planetary_nodes(dt)Verified low-level:
from moira.planetary_nodes import all_planetary_nodes
nodes = all_planetary_nodes(jd_ut)The original draft's exact lunar_nodes(...) / next_moon_node_crossing(...)
mapping is not yet audited here.
Verified facade:
from moira import Moira
m = Moira()
events = m.phenomena("Venus", jd_start, jd_end)
phases = m.moon_phases(jd_start, jd_end)Verified low-level:
from moira.phenomena import moon_phases_in_range
phases = moon_phases_in_range(jd_start, jd_end)Important correction:
- The original draft's
planetary_phenomena(...)function name is not yet audited as a current public function in this repo.
The following original-draft areas still need explicit symbol-by-symbol review before they can be treated as authoritative:
- exact Swiss flag-to-keyword mapping table
- body constant mapping table
- house-system code mapping table
- coordinate transform helper mapping
- heliacal mapping
- occultation mapping
- gauquelin mapping details
- asteroid and arbitrary-body migration examples
- "not yet implemented" completeness table
This is not yet the full 420-symbol matrix, but it is now explicit about what is already covered versus what still needs inclusion.
| Swiss symbol / family | Current Moira status | Current Moira surface | Notes |
|---|---|---|---|
set_ephe_path, set_jpl_file
|
mapped |
Moira(kernel_path=...), set_kernel_path(...)
|
semantic equivalent |
set_topo |
unsupported.design | per-call observer_lat, observer_lon, observer_elev_m
|
Moira is stateless by design; global observer state is unsupported.design; per-call observer kwargs are the correct idiom; Group A audit 2026-04-06 |
close |
unsupported | none | no C-handle lifecycle |
julday, revjul
|
mapped |
julian_day, calendar_from_jd
|
verified |
UTC datetime -> JD
|
mapped | jd_from_datetime |
verified |
deltat |
mapped |
delta_t_from_jd(jd_ut) in moira.julian; delta_t(year_decimal) also available |
JD-native wrapper added; delegates to delta_t via decimal_year_from_jd
|
sidtime |
mapped | greenwich_mean_sidereal_time |
verified |
calc_ut |
mapped |
planet_at(body, jd_ut) → PlanetData in moira.planets; returns longitude, latitude, distance, speed; m.chart(), m.sky_position() as facade equivalents |
architectural split is intentional; Group C audit 2026-04-06 |
calc |
mapped |
planet_at(body, jd_ut, jd_tt=...) in moira.planets; jd_tt kwarg skips UT→TT conversion for direct TT input |
TT fast path confirmed at planets.py:608
|
houses, houses_ex
|
mapped |
calculate_houses(...), m.houses(...)
|
verified |
set_sid_mode, get_ayanamsa_ut
|
unsupported.design / mapped |
ayanamsa(jd_ut, Ayanamsa.X) in moira.sidereal; Ayanamsa.LAHIRI → 'Lahiri'
|
set_sid_mode is unsupported.design; get_ayanamsa_ut maps to ayanamsa(jd_ut, Ayanamsa.X); Group A/C audit 2026-04-06 |
fixstar_ut, fixstar_mag
|
mapped |
fixed_star_at(...), star_magnitude(...), m.fixed_star(...)
|
verified |
sol_eclipse_*, lun_eclipse_*
|
mapped |
EclipseCalculator, m.eclipse(...)
|
global search, local circumstances, path geometry, analysis bundle all mapped; sol_eclipse_when_loc → next_solar_eclipse_at_location(jd_start, lat, lon) free function (location-anchored search); Group E/F complete 2026-04-06 |
rise_trans, rise_trans_true_hor
|
mapped |
find_phenomena(...), get_transit(...)
|
find_phenomena returns Rise/Set/Transit/AntiTransit; altitude kwarg and RiseSetPolicy(horizon_altitude=...) cover true-horizon; Group G audit 2026-04-04 |
nod_aps_ut |
mapped |
nodes_and_apsides_at(body, jd_ut) → NodesAndApsides in moira.nodes; Moon: true_node + true_lilith; planets: planetary_node from moira.planetary_nodes
|
NodesAndApsides.ascending_node_lon, descending_node_lon, periapsis_lon, apoapsis_lon; Group E vessel added 2026-04-06 |
pheno_ut |
mapped |
planet_phenomena_at(body, jd_ut) → PlanetPhenomena in moira.phenomena
|
phase_angle_deg, illuminated_fraction, elongation_deg, angular_diameter_arcsec, apparent_magnitude; Group E vessel added 2026-04-06 |
heliacal_ut and heliacal phenomena |
mapped |
planet_heliacal_rising(body, jd_start, lat, lon), planet_heliacal_setting(...), visibility_event(body, HeliacalEventKind.X, ...) in moira.heliacal
|
planets and general bodies covered; Group C audit 2026-04-06 |
azalt, azalt_rev, cotrans
|
mapped |
equatorial_to_horizontal(ra_deg, dec_deg, lst_deg, lat_deg), horizontal_to_equatorial, ecliptic_to_equatorial, equatorial_to_ecliptic in moira.coordinates
|
azalt takes pre-computed LST (degrees); all three symbols fully mapped; Group C audit 2026-04-06 |
refrac, refrac_extended
|
mapped |
atmospheric_refraction(...), atmospheric_refraction_extended(...) in moira.coordinates
|
Phase 1 |
degnorm |
mapped | coordinates.normalize_degrees(...) |
verified |
mooncross_ut, solcross_ut
|
mapped |
next_transit(Body.MOON/SUN, target_lon, jd_start) → TransitEvent in moira.transits
|
exact semantic match; Group C audit 2026-04-06 |
gauquelin_sector |
mapped |
moira.gauquelin.gauquelin_sector(...), all_gauquelin_sectors(...), m.gauquelin_sectors(...)
|
verified |
lun_occult_when_glob, lun_occult_when_loc family |
mapped |
lunar_occultation(target, jd_start, jd_end), lunar_star_occultation(...), lunar_occultation_path_at(...), lunar_star_occultation_path_at(...)
|
both accept observer_lat/observer_lon for local search; OccultationPathGeometry for path; IOTA-validated; Group F audit 2026-04-04 |
| station / retrograde search | mapped |
find_stations, retrograde_periods, m.stations, m.retrograde_periods
|
verified |
| returns / syzygy / ingresses | mapped |
solar_return, lunar_return, planet_return, prenatal_syzygy, find_ingresses, next_ingress, facade methods |
verified |
| asteroid body access | mapped |
asteroid_at, main_belt_at, centaur_at, tno_at, available_in_kernel
|
verified |
| Uranian bodies | mapped |
moira.uranian, m.uranian(...)
|
draft incorrectly implied missing support |
These are the items from the generated draft that still look genuinely absent or not yet verified as present in the current repo.
set_lapse_ratelat_to_lmtlmt_to_latget_current_file_dataget_library_pathget_tid_accset_tid_acc
- full Swiss flag table (
FLG_*) - full body constant table against current Moira naming
- full ayanamsa constant table against
moira.sidereal.Ayanamsa - exact house-system byte-code mapping table
- exact coordinate-transform helper parity
- exact planetary-phenomena parity with Swiss
pheno_ut
- lunar occultations
- star occultation support
- Uranian bodies
- asteroid kernel introspection
- station and retrograde search
- returns and syzygy helpers
Based on this pass alone, the honest "needs inclusion" list is much smaller than the generated draft implied.
High confidence missing utility surface:
- explicit tidal-acceleration override getters/setters if Swiss parity matters
- Swiss-style local-mean-time helper utilities if you want migration parity
- any file-introspection helpers analogous to Swiss library/file-path queries
Everything else above should be treated as "needs exact mapping work" before it is treated as missing.
This section is the more literal inventory pass: one row per Swiss symbol named in the generated draft, with the best current status from this audit.
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
set_ephe_path |
mapped |
Moira(kernel_path=...), set_kernel_path(...)
|
semantic equivalent |
set_jpl_file |
mapped |
Moira(kernel_path=...), set_kernel_path(...)
|
kernel path instead of file-name switch |
set_topo |
unsupported.design | per-call observer_lat, observer_lon, observer_elev_m
|
Moira is stateless by design; global observer state is unsupported.design; per-call observer kwargs are the correct idiom; Group A audit 2026-04-06 |
close |
unsupported | none | no C-library lifecycle |
set_delta_t_userdef |
mapped |
DeltaTPolicy in moira.julian
|
Phase 1; covers ΔT model and user override |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
julday |
mapped | moira.julian.julian_day(...) |
verified |
revjul |
mapped | moira.julian.calendar_from_jd(...) |
verified |
utc_to_jd |
mapped |
jd_from_datetime(dt: datetime) → float in moira.julian
|
confirmed in julian.__all__; Group C audit 2026-04-06 |
jdet_to_utc |
mapped |
calendar_datetime_from_jd(jd) → CalendarDateTime; datetime_from_jd(jd) → datetime in moira.julian
|
TT input accepted; typed vessel or Python datetime returned; Group C audit 2026-04-06 |
jdut1_to_utc |
mapped |
datetime_from_jd(jd) → datetime in moira.julian
|
Moira does not expose a UT1-specific variant; UT1/UTC difference is sub-millisecond for practical use; Group C audit 2026-04-06 |
deltat |
mapped |
delta_t_from_jd(jd_ut) in moira.julian; delta_t(year_decimal) also available |
JD-native wrapper added |
deltat_ex |
mapped |
DeltaTPolicy(model=..., fixed_delta_t=...) for algorithm selection; delta_t_nasa_canon(year: float) for the extended NASA algorithm |
flags replaced by explicit policy; Group C audit 2026-04-06 |
sidtime |
mapped | greenwich_mean_sidereal_time(...) |
verified |
sidtime0 |
mapped |
apparent_sidereal_time_at(jd_ut, longitude=0.0) in moira.julian; longitude=0 → GAST, non-zero → LAST |
wrapper added; nutation and obliquity derived internally |
time_equ |
mapped |
equation_of_time(jd_tt) in moira.coordinates
|
Phase 1 |
day_of_week |
stdlib |
datetime.weekday() / calendar.day_name[datetime.weekday()]
|
Python stdlib; no Moira helper needed; Group B audit 2026-04-06 |
utc_time_zone |
stdlib | Python datetime/zoneinfo or Qt timezone handling |
not a Moira concern |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
calc_ut |
mapped |
planet_at(body, jd_ut) → PlanetData in moira.planets; returns longitude, latitude, distance, speed; m.chart(), m.sky_position() as facade equivalents |
architectural split is intentional; Group C audit 2026-04-06 |
calc |
mapped |
planet_at(body, jd_ut, jd_tt=...) in moira.planets; jd_tt kwarg skips UT→TT conversion for direct TT input |
TT fast path confirmed at planets.py:608
|
calc_pctr |
mapped |
planet_relative_to(...) in moira.planets
|
Phase 2 |
get_planet_name |
stdlib | body strings are self-describing; body constants carry their names directly | no dedicated helper needed; Group B audit 2026-04-06 |
get_orbital_elements |
mapped |
orbital_elements_at(body, jd_ut) → KeplerianElements in moira.orbits
|
Phase 4 |
orbit_max_min_true_distance |
mapped |
distance_extremes_at(body, jd_ut) → DistanceExtremes in moira.orbits
|
Phase 4 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
houses |
mapped |
calculate_houses(...), m.houses(...)
|
verified |
houses_ex |
mapped |
calculate_houses(jd_ut, lat, lon, system, *, ayanamsa_offset=...) in moira.houses
|
pass ayanamsa_offset=ayanamsa(jd_ut, Ayanamsa.LAHIRI) for sidereal; explicit idiom |
houses_ex2 |
mapped |
cusp_speeds_at(jd_ut, lat, lon, system) → HouseDynamics in moira.houses
|
Phase 3; finite-difference cusp speeds, same method Swiss uses internally; idiom differs |
houses_armc |
mapped |
houses_from_armc(...) in moira.houses
|
Phase 2 |
houses_armc_ex2 |
mapped |
house_dynamics_from_armc(armc, obliquity, lat, system, *, ayanamsa_offset=...) — houses_from_armc now accepts ayanamsa_offset; house_dynamics_from_armc for speeds |
ARMC sidereal + speeds covered by both |
house_pos |
mapped |
body_house_position(...) in moira.houses
|
Phase 2 |
house_name |
mapped |
HOUSE_SYSTEM_NAMES[system] in moira.constants
|
dict lookup; same data, explicit idiom |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
set_sid_mode |
unsupported.design | per-call ayanamsa(jd_ut, Ayanamsa.X) is the correct idiom |
Moira has no global sidereal mode; unsupported.design; Group A audit 2026-04-06 |
get_ayanamsa_ut |
mapped | moira.sidereal.ayanamsa(...) |
verified function, different name |
get_ayanamsa_ex_ut |
mapped |
ayanamsa(jd_ut, Ayanamsa.X) → float in moira.sidereal
|
flags replaced by explicit per-call ayanamsa selection; Group C audit 2026-04-06 |
get_ayanamsa_name |
mapped |
Ayanamsa.LAHIRI returns 'Lahiri' directly (plain string-constant class, not StrEnum); the string value is the name |
Group C audit 2026-04-06 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
fixstar_ut |
mapped |
fixed_star_at(...), m.fixed_star(...)
|
low-level TT, facade datetime |
fixstar2_ut |
mapped |
fixed_star_at(...), m.fixed_star(...)
|
same current star pipeline |
fixstar_mag |
mapped | star_magnitude(...) |
verified |
fixstar2_mag |
mapped | star_magnitude(...) |
verified |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
sol_eclipse_when_glob |
mapped | EclipseCalculator().next_solar_eclipse(jd_start) → EclipseEvent |
global search, no location argument; Group F audit 2026-04-04 |
sol_eclipse_when_loc |
mapped |
next_solar_eclipse_at_location(jd_start, lat, lon) → SolarEclipseLocalCircumstances in moira.eclipse; EclipseCalculator().next_solar_eclipse_at_location(...) method |
scans lunations from jd_start; locates each geocentric eclipse season; rejects eclipses where Sun is below horizon at observer; refines local maximum via ternary search; returns circumstances at local greatest eclipse instant; kind filter: 'any'/'total'/'annular'/'partial'/'central'/'hybrid'; implemented 2026-04-06 |
sol_eclipse_where |
mapped | EclipseCalculator().solar_eclipse_path(jd_start) → SolarEclipsePath |
central_line_lats/lons, umbral_width_km, duration_at_max_s, max_eclipse_lat/lon; validated against Swiss where fixture; Group F audit 2026-04-04 |
sol_eclipse_how |
mapped |
EclipseCalculator().solar_local_circumstances(...) → SolarEclipseLocalCircumstances
|
event.data.eclipse_magnitude, sun_apparent_radius, moon_apparent_radius, topocentric_separation_deg, topocentric_overlap; Group F audit 2026-04-04 |
lun_eclipse_when |
mapped | EclipseCalculator().next_lunar_eclipse(jd_start) → EclipseEvent |
global search; Group F audit 2026-04-04 |
lun_eclipse_when_loc |
mapped | EclipseCalculator().lunar_local_circumstances(jd_start, lat, lon) → LunarEclipseLocalCircumstances |
per-contact LocalContactCircumstances (jd_ut, azimuth, altitude, visible) for P1/U1/U2/U3/U4/P4/greatest; Group F audit 2026-04-04 |
lun_eclipse_how |
mapped | LunarEclipseLocalCircumstances.analysis → LunarEclipseAnalysis |
eclipse_magnitude, eclipse_type, gamma_earth_radii, shadow radii on EclipseData; Group F audit 2026-04-04 |
lun_occult_when_glob |
mapped |
lunar_occultation(target, jd_start, jd_end), lunar_star_occultation(...), all_lunar_occultations(...)
|
omit observer_lat/observer_lon for geocentric global search; Group F audit 2026-04-04 |
lun_occult_when_loc |
mapped |
lunar_occultation(target, jd_start, jd_end, observer_lat=lat, observer_lon=lon), lunar_star_occultation(..., observer_lat=lat, observer_lon=lon)
|
topocentric search when observer coords supplied; Group F audit 2026-04-04 |
lun_occult_where |
mapped |
lunar_occultation_path_at(target, jd_mid) → OccultationPathGeometry, lunar_star_occultation_path_at(...)
|
central_line_lats/lons, path_width_km, duration_at_greatest_s; IOTA-validated; Group F audit 2026-04-04 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
rise_trans |
mapped | find_phenomena(body, jd_start, lat, lon) → dict |
returns 'Rise', 'Set', 'Transit', 'AntiTransit' keys; covers all Swiss CALC_RISE/CALC_SET/CALC_MTRANSIT/CALC_ITRANSIT use cases; Group G audit 2026-04-04 |
rise_trans_true_hor |
mapped |
find_phenomena(body, jd_start, lat, lon, altitude=<val>) or RiseSetPolicy(horizon_altitude=<val>)
|
explicit altitude override drives the bisection threshold; refraction=False gives geometric (no-atmosphere) horizon; Group G audit 2026-04-04 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
nod_aps_ut |
mapped |
nodes_and_apsides_at(body, jd_ut) → NodesAndApsides in moira.nodes
|
ascending_node_lon, descending_node_lon, periapsis_lon, apoapsis_lon; planetary side from planetary_nodes; lunar side from true_node + true_lilith; Group E vessel added 2026-04-06 |
mooncross_node_ut |
mapped |
next_moon_node_crossing(...) in moira.nodes
|
Phase 2 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
pheno_ut |
mapped |
planet_phenomena_at(body, jd_ut) → PlanetPhenomena in moira.phenomena
|
phase_angle_deg, illuminated_fraction, elongation_deg, angular_diameter_arcsec, apparent_magnitude; Group E vessel added 2026-04-06 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
heliacal_ut |
mapped |
planet_heliacal_rising(body, jd_start, lat, lon) → PlanetHeliacalEvent, planet_heliacal_setting(...) in moira.heliacal; visibility_event(body, HeliacalEventKind.X, ...) for general case |
planets and general bodies covered; Group C audit 2026-04-06 |
heliacal_pheno_ut |
mapped |
visibility_assessment(body, jd_ut, lat, lon, *, policy) -> VisibilityAssessment in moira.heliacal
|
VisibilityAssessment.solar_elongation_deg + altitude + limiting magnitude constitute the phenomena tuple; Phase 5 / V6 |
vis_limit_mag |
mapped |
visual_limiting_magnitude(jd_ut, lat, lon, *, policy) in moira.heliacal
|
Phase 5 / V6; Bortle sky limit + K&S 1991 moonlight penalty |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
azalt |
mapped |
equatorial_to_horizontal(ra_deg, dec_deg, lst_deg, lat_deg) → tuple[float, float] in moira.coordinates
|
takes pre-computed LST in degrees; returns (azimuth_deg, altitude_deg); Group C audit 2026-04-06 |
azalt_rev |
mapped |
horizontal_to_equatorial(...) in moira.coordinates
|
Phase 1 |
cotrans |
mapped |
ecliptic_to_equatorial(...), equatorial_to_ecliptic(...)
|
verified |
cotrans_sp |
mapped |
cotrans_sp(...) in moira.coordinates
|
Phase 1 |
refrac |
mapped |
atmospheric_refraction(...) in moira.coordinates
|
Phase 1 |
refrac_extended |
mapped |
atmospheric_refraction_extended(...) in moira.coordinates
|
Phase 1 |
degnorm |
mapped | normalize_degrees(...) |
verified |
radnorm |
stdlib | Python math modulo |
no dedicated Moira helper needed |
difdeg2n |
mapped |
normalize_degrees(a - b) in moira.coordinates
|
idiomatic one-liner; Group B audit 2026-04-06 |
deg_midp |
mapped |
normalize_degrees((a + b) / 2) for same-hemisphere; normalize_degrees((a + b + 360) / 2) for cross-zero case |
idiomatic one-liner; Group B audit 2026-04-06 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
mooncross_ut |
mapped |
next_transit(Body.MOON, target_lon, jd_start) → TransitEvent in moira.transits
|
exact semantic match; Group C audit 2026-04-06 |
solcross_ut |
mapped |
next_transit(Body.SUN, target_lon, jd_start) → TransitEvent in moira.transits
|
exact semantic match; Group C audit 2026-04-06 |
helio_cross_ut |
mapped |
next_heliocentric_transit(...) in moira.planets
|
Phase 2 |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
gauquelin_sector |
mapped |
moira.gauquelin.gauquelin_sector(...), all_gauquelin_sectors(...), m.gauquelin_sectors(...)
|
verified |
| Swiss symbol | Status | Current Moira equivalent | Notes |
|---|---|---|---|
split_deg |
stdlib | local arithmetic | no dedicated audited helper |
cs2degstr |
stdlib | formatting | no dedicated audited helper |
d2l |
stdlib | int(...) |
no Moira helper needed |
csnorm |
unsupported | none | not meaningful for Moira API surface |
| Swiss symbol / family | Status | Current Moira equivalent | Notes |
|---|---|---|---|
AST_OFFSET + n asteroid access |
mapped |
asteroid_at(...), main_belt_at(...), centaur_at(...), tno_at(...)
|
verified |
Uranian bodies CUPIDO..POSEIDON
|
mapped |
moira.uranian, m.uranian(...)
|
verified |
SE_ISIS (asteroid 42 Isis) |
mapped |
asteroid_at("Isis", jd_ut) via NAIF ID 2000042 in asteroid catalog |
real minor planet with valid SPK entry; Group H audit 2026-04-04 |
SE_NIBIRU |
unsupported | none | no accepted scientific ephemeris, no NAIF ID, no SPK kernel; fictional body; unsupported.doctrine
|
SE_HARRINGTON |
unsupported | none | Harrington's never-confirmed Planet X hypothesis; no NAIF ID, no SPK kernel exists; unsupported.doctrine
|
If Swiss parity is the goal, these are the clearest items still needing real Moira surface rather than just mapping work:
Implemented (Phase 1–4):
-
DeltaTPolicyclosesset_delta_t_userdef(Phase 1) -
horizontal_to_equatorialclosesazalt_rev(Phase 1) -
atmospheric_refraction/atmospheric_refraction_extendedcloserefrac/refrac_extended(Phase 1) -
equation_of_timeclosestime_equ(Phase 1) -
houses_from_armc/body_house_positionclosehouses_armc/house_pos(Phase 2) -
planet_relative_toclosescalc_pctr(Phase 2) -
next_moon_node_crossingclosesmooncross_node_ut(Phase 2) -
next_heliocentric_transitcloseshelio_cross_ut(Phase 2) -
orbital_elements_at/distance_extremes_atcloseget_orbital_elements/orbit_max_min_true_distance(Phase 4) -
visual_limiting_magnitudeclosesvis_limit_mag(Phase 5 / V6) -
ayanamsa_offsetkwarg oncalculate_housesandhouses_from_armccloseshouses_ex/houses_armc_ex2sidereal parity -
VisibilityAssessment.solar_elongation_degclosesheliacal_pheno_ut(Phase 5 / V6)
Still missing:
- local-mean-time utility helpers (
lat_to_lmt,lmt_to_lat) - tidal-acceleration override helpers (
get_tid_acc,set_tid_acc) - library/file introspection helpers (
get_library_path,get_current_file_data)
If you are migrating off pyswisseph today, prefer this Moira shape:
from moira import Moira
from moira.constants import HouseSystem
from moira.planets import planet_at, sky_position_at
from moira.rise_set import find_phenomena, get_transit
from moira.sidereal import Ayanamsa, ayanamsa
m = Moira(kernel_path="/path/to/de441.bsp")
chart = m.chart(dt, observer_lat=lat, observer_lon=lon)
houses = m.houses(dt, lat, lon, HouseSystem.PLACIDUS)
sun = chart.planets["Sun"]
moon_sky = m.sky_position(dt, "Moon", lat, lon)
events = find_phenomena("Sun", jd_start, lat, lon)
lahiri = ayanamsa(jd_ut, Ayanamsa.LAHIRI)This draft should be extended only by checking each claimed mapping against the live repo surface first.