GreenCal.Astro (GreenCal v0.2.0)

Copy Markdown View Source

Low-level facade: apparent positions, phase, rises and sets.

This is where UT and TT are reconciled. Every public function in this module takes a Julian day in UT and applies ΔT itself before calling GreenCal.Astro.Sun / GreenCal.Astro.Moon.

For the garden-oriented API, see GreenCal.

Summary

Functions

Perigee and apogee instants between two UT Julian days.

Lunar standstill instants between two UT Julian days: the extrema of the Moon's declination, i.e. the exact moments the Moon switches from ascending to descending (:northernmost) and back (:southernmost).

Apparent position of the Moon for a UT Julian day.

Rises, sets and meridian transit of the Moon between two UT Julian days.

Lunar node crossings between two UT Julian days.

Elongation, phase angle and illuminated fraction of the Moon.

Exact instants of the principal lunar phases between two UT Julian days.

Phase name from the elongation λ☾ − λ☉, in eight sectors.

Apparent position of the Sun for a UT Julian day.

Rises, sets and meridian transit of the Sun between two UT Julian days.

Dawn and dusk for a given solar altitude.

Functions

apsis_events(jd_from, jd_to, opts \\ [])

@spec apsis_events(float(), float(), keyword()) :: [
  %{type: :perigee | :apogee, jd: float(), distance_km: float()}
]

Perigee and apogee instants between two UT Julian days.

Extrema of the Earth–Moon distance (anomalistic month, 27.55 days), located as zero crossings of the centered derivative. Returns %{type: :perigee | :apogee, jd: float, distance_km: float} in chronological order.

declination_extrema(jd_from, jd_to, opts \\ [])

@spec declination_extrema(float(), float(), keyword()) :: [
  %{type: :northernmost | :southernmost, jd: float(), declination: float()}
]

Lunar standstill instants between two UT Julian days: the extrema of the Moon's declination, i.e. the exact moments the Moon switches from ascending to descending (:northernmost) and back (:southernmost).

This is the boundary printed in biodynamic sowing calendars. Half a tropical month (~13.7 days) apart. Returns %{type: :northernmost | :southernmost, jd: float, declination: float}.

moon(jd, opts \\ [])

@spec moon(
  float(),
  keyword()
) :: GreenCal.Astro.Moon.position()

Apparent position of the Moon for a UT Julian day.

moon_events(loc, jd_from, jd_to, opts \\ [])

@spec moon_events({number(), number()}, float(), float(), keyword()) ::
  GreenCal.Astro.RiseSet.result()

Rises, sets and meridian transit of the Moon between two UT Julian days.

Here h₀ depends on the instantaneous distance (parallax), so it is recomputed at every evaluation — see GreenCal.Astro.Moon.horizon_altitude/1.

node_crossings(jd_from, jd_to, opts \\ [])

@spec node_crossings(float(), float(), keyword()) :: [
  %{type: :ascending | :descending, jd: float()}
]

Lunar node crossings between two UT Julian days.

A node crossing is the instant the Moon crosses the ecliptic plane (ecliptic latitude β = 0): :ascending when β turns positive, :descending when it turns negative. They occur every ~13.6 days (half a draconic month) and are geocentric — no location involved.

Biodynamic calendars mark the hours around a node crossing as unfavorable for sowing; eclipses can only happen near one.

Returns a list of %{type: :ascending | :descending, jd: float} in chronological order.

phase(jd, opts \\ [])

@spec phase(
  float(),
  keyword()
) :: %{
  elongation: float(),
  phase_angle: float(),
  illuminated_fraction: float(),
  angular_separation: float()
}

Elongation, phase angle and illuminated fraction of the Moon.

The phase angle follows Meeus 48.3, using the true Earth–Sun and Earth–Moon distances rather than the approximate series of chapter 47: more accurate, and free since the Sun is computed anyway.

:elongation is the ecliptic longitude difference λ☾ − λ☉ reduced into [0, 360) — this, not the true angular elongation, is what defines the phases (0 = new moon, 180 = full moon).

phase_events(jd_from, jd_to, opts \\ [])

@spec phase_events(float(), float(), keyword()) :: [
  %{type: atom(), jd: float(), eclipse: :none | :possible | :likely}
]

Exact instants of the principal lunar phases between two UT Julian days.

Returns a chronological list of

%{type: :new_moon | :first_quarter | :full_moon | :last_quarter,
  jd: float,
  eclipse: :none | :possible | :likely}

The instant is where the elongation λ☾ − λ☉ crosses 0°, 90°, 180° or 270° (the standard definition of the phases), found by bisection on the apparent longitudes — so ΔT and nutation are accounted for.

:eclipse is a screening flag, not an eclipse computation: at a new moon (solar eclipse) or full moon (lunar eclipse), an eclipse can only happen if the Moon is close enough to the ecliptic. |β| < 1.2°:likely, |β| < 1.9°:possible (thresholds from Meeus ch. 54's argument-of-latitude criterion). It says an eclipse happens somewhere on Earth — visibility, magnitude and local circumstances are out of scope. Quarters always carry :none.

phase_name(elongation)

@spec phase_name(float()) :: atom()

Phase name from the elongation λ☾ − λ☉, in eight sectors.

Each of the four principal phases owns a 22.5° sector centered on its exact value: :full_moon therefore names the day around the exact instant, not just the instant.

sun(jd, opts \\ [])

@spec sun(
  float(),
  keyword()
) :: GreenCal.Astro.Sun.position()

Apparent position of the Sun for a UT Julian day.

sun_events(loc, jd_from, jd_to, opts \\ [])

@spec sun_events({number(), number()}, float(), float(), keyword()) ::
  GreenCal.Astro.RiseSet.result()

Rises, sets and meridian transit of the Sun between two UT Julian days.

Options: :elevation (meters, default 0), :delta_t, plus those of GreenCal.Astro.RiseSet.search/5.

twilight_events(loc, jd_from, jd_to, kind, opts \\ [])

@spec twilight_events(
  {number(), number()},
  float(),
  float(),
  atom() | number(),
  keyword()
) ::
  GreenCal.Astro.RiseSet.result()

Dawn and dusk for a given solar altitude.

Accepts :civil (−6°), :nautical (−12°), :astronomical (−18°), or a number of degrees — e.g. 6.0 for the golden hour.

Unlike a computation derived from sunrise, this one stays valid when the Sun does not rise: civil twilight does happen above the polar circle in winter.

:elevation deliberately does not apply here: twilights are defined by the Sun's geometric altitude, not by its visibility over the local horizon, so observer height changes sunrise but not dawn.