# `Astro.Solar.Eclipse`
[🔗](https://github.com/kipcole9/astro/blob/v2.11.0/lib/astro/solar/eclipse.ex#L1)

Solar eclipses: finding them, classifying them and measuring them,
from the Besselian elements of the Moon's shadow.

A solar eclipse can only happen at a new moon near a node of the
Moon's orbit, when the shadow the Moon casts away from the Sun falls
on the Earth. The shadow is two cones with a common axis, the line
through the centres of the Sun and the Moon: the penumbra, from which
some of the Sun is seen, and the umbra, from which none of it is. The
umbra narrows to a vertex about as far from the Moon as the Earth is;
beyond it, the antumbra, the Moon is seen inside the Sun's disk.

### The Besselian elements

The shadow is described on the *fundamental plane*, through the
centre of the Earth and perpendicular to the shadow axis, with the
Earth's equatorial radius as the unit of length. At any instant the
Besselian elements give:

* `x` and `y`, where the axis crosses the plane, with `y` towards
  the north and `x` towards the east.

* `d` and `μ`, the declination and Greenwich hour angle of the axis,
  which turn the plane into places on the Earth.

* `l1` and `l2`, the radii of the penumbra and the umbra on the
  plane, `l2` negative where the umbra reaches beyond it.

* `tan f1` and `tan f2`, the slopes of the two cones, which give
  their radii at an observer's distance above the plane.

`elements/1` computes them from the Sun's and the Moon's apparent
geocentric positions and distances, the method of the *Explanatory
Supplement*: the axis is the direction from the Moon to the Sun, the
Moon's position is turned into the frame of the plane, and the cones
follow from the radii of the Sun and the Moon. The Moon's radius is
`k1 = 0.272488` Earth radii for the penumbra and `k2 = 0.272281`, a
mean below the peaks of its limb, for the umbra, as NASA's catalogues
use them, so that a total phase is not overstated.

NASA publishes `μ` as an *ephemeris* hour angle, computed as if
Terrestrial Time were Universal Time, and an observer's longitude is
corrected by ΔT to use it. `elements/1` returns the Greenwich hour
angle at the moment itself, which needs no correction, so the two
differ by ΔT's worth of the Earth's rotation, about 0.29° in 2024.

### Greatest eclipse, gamma and the type

*Greatest eclipse* is the moment the shadow axis passes closest to
the centre of the Earth, the least `√(x² + y²)`, found by golden
section search around each new moon. *Gamma* is that distance,
positive when the axis passes north of the centre.

On the plane the Earth is an ellipse, of semi-axes 1 and
`√(1 − e² cos² d)` for the Earth's flattening. Where the axis meets
it, the eclipse is *central*, and its kind depends on the umbra where
the axis meets the surface, at a height `ζ` above the plane: total
where `l2 − ζ tan f2` is negative, annular where it is positive. The
point of greatest eclipse is nearer the Sun than the limb, where the
central line begins and ends, so a total eclipse whose umbra stops
short of the surface at either end is *hybrid*. Where the axis
misses the Earth but the umbra or antumbra still reaches it, the
eclipse is total or annular without a central line; where only the
penumbra does, it is partial.

### Magnitude

For a central eclipse the magnitude is the ratio of the Moon's
apparent diameter to the Sun's at the point of greatest eclipse,
`(L1 − L2) / (L1 + L2)`, where `L1` and `L2` are the cones' radii
there. Otherwise it is the fraction of the Sun's diameter covered at
the point of the Earth's limb nearest the axis, `(l1 − Δ) / (l1 + l2)`,
where `Δ` is that point's distance from the axis; NASA's catalogues
use it for a total or annular eclipse without a central line too.

How an eclipse is seen from a place, its local circumstances, is
computed from the same elements by `Astro.Solar.Eclipse.Local`.

The Sun's and the Moon's apparent geocentric positions and distances
are those of `Astro.sun_position_at/1` and `Astro.moon_position_at/1`:
from the JPL ephemeris where the loaded kernel covers the moment, and
from the analytical series elsewhere.

# `eclipse_type`

```elixir
@type eclipse_type() :: :partial | :annular | :total | :hybrid
```

The kind of solar eclipse: only the penumbra reaches the Earth, the
antumbra does, the umbra does, or the shadow changes from one to the
other along its path.

# `elements`

```elixir
@type elements() :: %{
  x: float(),
  y: float(),
  d: float(),
  mu: float(),
  l1: float(),
  l2: float(),
  tan_f1: float(),
  tan_f2: float()
}
```

The Besselian elements of the Moon's shadow at a moment. Lengths are
in equatorial radii of the Earth and angles in degrees.

# `t`

```elixir
@type t() :: %Astro.Solar.Eclipse{
  gamma: float(),
  greatest: DateTime.t(),
  magnitude: float(),
  saros: integer(),
  type: eclipse_type()
}
```

A solar eclipse. Greatest eclipse is a UTC `t:DateTime.t/0`, and the
Saros series is numbered as NASA numbers it (`Astro.Saros`).

# `eclipse_at_or_after`

```elixir
@spec eclipse_at_or_after(Astro.Time.moment()) :: {:ok, map()} | {:error, :no_eclipse}
```

Returns the circumstances of the first solar eclipse whose greatest
eclipse is at or after a moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` within 50,000 years of J2000.

### Returns

* `{:ok, circumstances}`, a map with the keys of `t:t/0`, greatest
  eclipse a moment.

* `{:error, :no_eclipse}` if none is found within 13 lunations, which
  does not happen.

### Examples

    iex> {:ok, eclipse} = Astro.Solar.Eclipse.eclipse_at_or_after(739_300.0)
    iex> {eclipse.type, Float.round(eclipse.gamma, 3)}
    {:total, 0.343}

# `eclipse_before`

```elixir
@spec eclipse_before(Astro.Time.moment()) :: {:ok, map()} | {:error, :no_eclipse}
```

Returns the circumstances of the last solar eclipse whose greatest
eclipse is before a moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0` within 50,000 years of J2000.

### Returns

* `{:ok, circumstances}`, a map with the keys of `t:t/0`, greatest
  eclipse a moment.

* `{:error, :no_eclipse}` if none is found within 13 lunations, which
  does not happen.

### Examples

    iex> {:ok, eclipse} = Astro.Solar.Eclipse.eclipse_before(739_400.0)
    iex> eclipse.type
    :total

# `elements`

```elixir
@spec elements(Astro.Time.moment()) :: elements()
```

Returns the Besselian elements of the Moon's shadow at a moment.

### Arguments

* `t` is a `t:Astro.Time.moment/0`.

### Returns

* A map with these keys, lengths in equatorial radii of the Earth and
  angles in degrees:

  * `:x` and `:y` — where the shadow axis crosses the fundamental
    plane, `:y` towards the north.

  * `:d` — the declination of the shadow axis.

  * `:mu` — the Greenwich hour angle of the shadow axis.

  * `:l1` and `:l2` — the radii of the penumbra and the umbra on the
    plane, `:l2` negative where the umbra reaches beyond it.

  * `:tan_f1` and `:tan_f2` — the slopes of the penumbral and umbral
    cones.

### Examples

At 18:00 TD on 8 April 2024, 17:58:51 UT, NASA's elements are
`x = −0.318157` and `y = 0.219747`:

    iex> elements = Astro.Solar.Eclipse.elements(739_349.749199)
    iex> {Float.round(elements.x, 3), Float.round(elements.y, 3)}
    {-0.318, 0.22}

---

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