# `Astro.Lunar`
[🔗](https://github.com/kipcole9/astro/blob/v2.1.0/lib/astro/lunar.ex#L1)

Calculates lunar position, phases, distance and related quantities.

This module provides the analytical (Meeus Ch. 47) periodic-term
series for the Moon’s ecliptic longitude, latitude and distance,
as well as derived quantities such as illuminated fraction,
parallax and angular semi-diameter. These functions underpin the
higher-level lunar API in `Astro` and the topocentric
moonrise/moonset algorithm in `Astro.Lunar.MoonRiseSet`.

## Lunar phases

The phase of the Moon is defined by the elongation — the
geocentric angle between the Moon and the Sun. A **new moon**
occurs at 0° elongation, **first quarter** at 90°, **full moon**
at 180° and **last quarter** at 270°.

Because the Moon’s orbital plane is tilted ~5.1° relative to
the ecliptic, a new moon can be up to ~5.2° from the Sun,
which is why a solar eclipse does not occur every month.

## Function groups

### Position and geometry

* `lunar_position/1` — ecliptic longitude, latitude and distance
* `lunar_ecliptic_longitude/1`, `lunar_latitude/1`, `lunar_distance/1`
* `lunar_altitude/2`, `topocentric_lunar_altitude/2`
* `equatorial_horizontal_parallax/1`, `topocentric_lunar_parallax/2`
* `angular_semi_diameter/1`, `horizontal_dip/1`

### Phases and illumination

* `lunar_phase_at/1` — phase angle (0–360°) at a moment
* `illuminated_fraction_of_moon/1`
* `new_moon_phase/0`, `full_moon_phase/0`, `first_quarter_phase/0`,
  `last_quarter_phase/0`

### New moon and phase search

* `date_time_new_moon_before/1`, `date_time_new_moon_at_or_after/1`,
  `date_time_new_moon_nearest/1`
* `date_time_lunar_phase_at_or_before/2`, `date_time_lunar_phase_at_or_after/2`
* `nth_new_moon/1`

### Fundamental arguments (Julian centuries)

* `mean_lunar_ecliptic_longitude/1`, `lunar_elongation/1`
* `solar_anomaly/1`, `lunar_anomaly/1`, `lunar_node/1`, `moon_node/1`

## Time convention

Most functions in this module accept a **moment** (fractional
days since the epoch 0000-01-01). Use `Astro.Time.date_time_to_moment/1`
to convert dates or datetimes. Functions that accept Julian centuries
note this in their documentation.

# `angular_semi_diameter`

```elixir
@spec angular_semi_diameter(t :: Astro.Time.moment()) :: Astro.angle()
```

Returns the Moon's angular semi-diameter in degrees for a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The angular semi-diameter as a float in degrees.

# `date_time_lunar_phase_at_or_after`
*since 0.5.0* 

```elixir
@spec date_time_lunar_phase_at_or_after(
  t :: Astro.Time.moment(),
  phase :: Astro.phase()
) ::
  Astro.Time.moment()
```

Returns the date time of a given
lunar phase at or after a given
date time or date.

### Arguments

* `t`, a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

* `phase` is the required lunar phase expressed
  as a float number of degrees between `0` and
  `360`

### Returns

* a `t:Astro.Time.moment/0` which is a float number of days
  since `0000-01-01`.

### Example

    iex> Astro.Lunar.date_time_lunar_phase_at_or_after(738368, Astro.Lunar.full_moon_phase())
    738389.5014214877

# `date_time_lunar_phase_at_or_before`
*since 0.5.0* 

```elixir
@spec date_time_lunar_phase_at_or_before(
  t :: Astro.Time.moment(),
  phase :: Astro.phase()
) ::
  Astro.Time.moment()
```

Returns the date time of a given
lunar phase at or before a given
moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

* `phase` is the required lunar phase expressed
  as a float number of degrees between `0.0` and
  `360.0`

### Returns

* A `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Example

    iex> Astro.Lunar.date_time_lunar_phase_at_or_before(738368, Astro.Lunar.new_moon_phase())
    738346.053171558

# `date_time_new_moon_at_or_after`
*since 0.5.0* 

```elixir
@spec date_time_new_moon_at_or_after(t :: Astro.Time.moment()) :: Astro.Time.moment()
```

Returns the date time of the new
moon at or after a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* a `t:Astro.Time.moment/0` which is a float number of days
  since `0000-01-01`

### Example

    iex> Astro.Lunar.date_time_new_moon_at_or_after(738390)
    738405.0359290199

# `date_time_new_moon_before`
*since 0.5.0* 

```elixir
@spec date_time_new_moon_before(t :: Astro.Time.moment()) :: Astro.Time.moment()
```

Returns the date time of the new
moon before a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* A `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Example

    iex> Astro.Lunar.date_time_new_moon_before 738390
    738375.5764772523

# `date_time_new_moon_nearest`
*since 2.0.0* 

```elixir
@spec date_time_new_moon_nearest(t :: Astro.Time.moment()) :: Astro.Time.moment()
```

Returns the moment of the new
moon nearest to a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* a `t:Astro.Time.moment/0` which is a float number of days
  since `0000-01-01`

### Example

    iex> Astro.Lunar.date_time_new_moon_nearest(738390)
    738375.5764755815

# `equatorial_horizontal_parallax`

```elixir
@spec equatorial_horizontal_parallax(t :: Astro.Time.moment()) :: Astro.angle()
```

Returns the Moon's equatorial horizontal parallax in degrees for a
given moment.

The horizontal parallax is the angle subtended by Earth's equatorial
radius as seen from the Moon, or equivalently the maximum apparent
displacement of the Moon caused by the observer being on Earth's surface
rather than its centre.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The equatorial horizontal parallax as a float in degrees.

### Examples

    iex> Astro.Lunar.equatorial_horizontal_parallax(738390)
    ...> |> Float.round(4)
    0.0167

# `first_quarter_phase`
*since 0.5.0* 

```elixir
@spec first_quarter_phase() :: Astro.phase()
```

Returns the first quarter phase angle in degrees.

### Returns

* `90.0`

### Examples

    iex> Astro.Lunar.first_quarter_phase()
    90.0

# `full_moon_phase`
*since 0.5.0* 

```elixir
@spec full_moon_phase() :: Astro.phase()
```

Returns the full moon phase angle in degrees.

### Returns

* `180.0`

### Examples

    iex> Astro.Lunar.full_moon_phase()
    180.0

# `horizontal_dip`

```elixir
@spec horizontal_dip(t :: Astro.Time.moment()) :: Astro.angle()
```

Returns the Moon's horizontal dip angle in degrees for a given moment.

The horizontal dip combines atmospheric refraction, the Moon's angular
semi-diameter and the equatorial horizontal parallax to define the
threshold altitude for moonrise/moonset.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The horizontal dip as a float in degrees (negative value).

# `illuminated_fraction_of_moon`
*since 0.6.0* 

```elixir
@spec illuminated_fraction_of_moon(Astro.Time.time()) :: float()
```

Returns the fractional illumination of the Moon
for a given moment as a float between 0.0 and 1.0.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The fractional illumination of the Moon as a float
  between `0.0` (new moon) and `1.0` (full moon).

### Examples

    iex> Astro.Lunar.illuminated_fraction_of_moon(738390)
    ...> |> Float.round(4)
    0.9951

# `last_quarter_phase`
*since 0.5.0* 

```elixir
@spec last_quarter_phase() :: Astro.phase()
```

Returns the last quarter phase angle in degrees.

### Returns

* `270.0`

### Examples

    iex> Astro.Lunar.last_quarter_phase()
    270.0

# `lunar_altitude`
*since 0.4.0* 

```elixir
@spec lunar_altitude(Astro.Time.moment(), Geo.PointZ.t()) :: Astro.angle()
```

Returns the Moon's geocentric altitude in degrees for a given moment
and observer location.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

* `location` is a `Geo.PointZ` struct with `{longitude, latitude, altitude}`
  coordinates.

### Returns

* The geocentric altitude in degrees, ranging from -180.0 to 180.0.

# `lunar_anomaly`

```elixir
@spec lunar_anomaly(c :: Astro.Time.julian_centuries()) :: Astro.angle()
```

Returns the Moon's mean anomaly in degrees for a given number of
Julian centuries from J2000.0.

### Arguments

* `c` is the number of Julian centuries from J2000.0.

### Returns

* The mean lunar anomaly as a float in degrees.

# `lunar_distance`
*since 0.6.0* 

```elixir
@spec lunar_distance(t :: Astro.Time.moment()) :: Astro.meters()
```

Returns the Moon's distance from the Earth in meters for a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The Earth-Moon distance as a float in meters.

### Examples

    iex> Astro.Lunar.lunar_distance(738390) |> trunc()
    381251299

# `lunar_elongation`

```elixir
@spec lunar_elongation(c :: Astro.Time.julian_centuries()) :: Astro.angle()
```

Returns the mean lunar elongation in degrees for a given number of
Julian centuries from J2000.0.

### Arguments

* `c` is the number of Julian centuries from J2000.0.

### Returns

* The mean elongation as a float in degrees.

# `lunar_latitude`
*since 0.6.0* 

```elixir
@spec lunar_latitude(Astro.Time.moment()) :: Astro.angle()
```

Returns the Moon's ecliptic latitude in degrees for a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The ecliptic latitude as a float in degrees.

### Examples

    iex> Astro.Lunar.lunar_latitude(738390) |> Float.round(4)
    -5.0099

# `lunar_node`

```elixir
@spec lunar_node(t :: Astro.Time.moment()) :: Astro.angle()
```

Returns the Moon's ascending node longitude in degrees for a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* The ascending node longitude as a float in degrees,
  ranging from -90.0 to 90.0.

# `lunar_phase_at`
*since 0.5.0* 

```elixir
@spec lunar_phase_at(t :: Astro.Time.moment()) :: Astro.angle()
```

Returns the lunar phase as a float number of degrees at
a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* the lunar phase as a float number of
  degrees.

### Example

    iex> Astro.Lunar.lunar_phase_at(738389.5007195644)
    179.9911519346108

    iex> Astro.Lunar.lunar_phase_at(738346.0544609067)
    0.013592004555277981

# `lunar_position`
*since 0.6.0* 

```elixir
@spec lunar_position(Astro.Time.moment()) ::
  {Astro.angle(), Astro.angle(), Astro.meters()}
```

Returns the Moon's equatorial position (right ascension, declination,
distance) for a given moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

### Returns

* A 3-tuple `{right_ascension, declination, distance}` where
  right ascension and declination are in degrees and distance
  is in meters.

### Examples

    iex> {ra, _dec, _dist} = Astro.Lunar.lunar_position(738390)
    iex> Float.round(ra, 2)
    -19.96

# `lunar_radius`

```elixir
@spec lunar_radius() :: Astro.kilometers()
```

Returns the lunar radius in kilometers.

The IAU 2015 value of 1737.4 km is used.

### Arguments

None.

### Returns

* The lunar radius as a float in kilometers.

### Examples

    iex> Astro.Lunar.lunar_radius()
    1737.4

# `mean_lunar_ecliptic_longitude`

```elixir
@spec mean_lunar_ecliptic_longitude(c :: Astro.Time.julian_centuries()) ::
  Astro.angle()
```

Returns the mean lunar ecliptic longitude in degrees for a given
number of Julian centuries from J2000.0.

### Arguments

* `c` is the number of Julian centuries from J2000.0.

### Returns

* The mean ecliptic longitude as a float in degrees.

# `moon_node`

```elixir
@spec moon_node(c :: Astro.Time.julian_centuries()) :: Astro.angle()
```

Returns the mean longitude of the Moon's ascending node in degrees
for a given number of Julian centuries from J2000.0.

### Arguments

* `c` is the number of Julian centuries from J2000.0.

### Returns

* The mean longitude of the ascending node as a float in degrees.

# `new_moon_phase`
*since 0.5.0* 

```elixir
@spec new_moon_phase() :: Astro.phase()
```

Returns the new moon phase angle in degrees.

### Returns

* `0.0`

### Examples

    iex> Astro.Lunar.new_moon_phase()
    0.0

# `solar_anomaly`

```elixir
@spec solar_anomaly(c :: Astro.Time.julian_centuries()) :: Astro.angle()
```

Returns the Sun's mean anomaly in degrees for a given number of
Julian centuries from J2000.0.

### Arguments

* `c` is the number of Julian centuries from J2000.0.

### Returns

* The mean solar anomaly as a float in degrees.

# `topocentric_lunar_parallax`

```elixir
@spec topocentric_lunar_parallax(t :: Astro.Time.moment(), location :: Geo.PointZ.t()) ::
  Astro.angle()
```

Returns the topocentric lunar parallax in degrees for a given moment
and observer location.

This is the observer-specific parallax (also called the parallax in
altitude), which varies with the observer's latitude and the Moon's
altitude above their horizon — as opposed to the equatorial horizontal
parallax returned by `equatorial_horizontal_parallax/1`, which is
location-independent.

### Arguments

* `t` is a `t:Astro.Time.moment/0` float number of days
  since `0000-01-01`.

* `location` is a `Geo.PointZ` struct with `{longitude, latitude, altitude}`
  coordinates.

### Returns

* The topocentric parallax as a float in degrees.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
