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

The path of a solar eclipse: where on the Earth it is total or
annular, as the central line and the northern and southern limits of
the umbra, or the antumbra, and where it is seen at all, as the
limits of the penumbra and the curves on the horizon where it begins
or ends at sunrise or sunset, through the time the shadow is on the
Earth.

The Besselian elements (see `Astro.Solar.Eclipse`) put the shadow on
the fundamental plane, through the centre of the Earth and
perpendicular to the shadow axis. On it the Earth is an ellipse, and
a point `(ξ, η)` inside it is on the surface at a height `ζ` above
the plane. Following the *Explanatory Supplement*, the auxiliary
declinations `d1` and `d2` turn the ellipsoid into a unit sphere,
`η1 = η / ρ1` and `ζ1 = √(1 − ξ² − η1²)`, and then

* `ζ = ρ2 (ζ1 cos(d1 − d2) − η1 sin(d1 − d2))`,

* `sin φ1 = η1 cos d1 + ζ1 sin d1`, the latitude on the sphere, and
  `tan φ = tan φ1 / √(1 − e²)` the geodetic latitude, and

* `H = atan2(ξ, ζ1 cos d1 − η1 sin d1)`, the hour angle of the
  shadow axis there, and `λ = H − μ` the east longitude.

### The central line

The *central line* is where the shadow axis meets the surface,
`ξ = x` and `η = y`. It begins and ends at sunrise and sunset, where
the axis grazes the Earth. Along it:

* The eclipse is *total* where the umbra's radius at the surface,
  `L2 = l2 − ζ tan f2`, is negative, and *annular* where it is
  positive. A hybrid eclipse changes from one to the other.

* The shadow moves over the observer at `(a, b)` on the plane, its
  own motion `(x′, y′)` less the observer's, which the Earth's
  rotation carries at `ξ′ = μ′ (ζ cos d − η sin d)` and
  `η′ = μ′ ξ sin d − ζ d′`. The *duration* of totality or annularity
  is the time to cross the shadow, `2 |L2| / √(a² + b²)`.

* The *path width* is the width of the band whose observers come
  within `|L2|` of the axis: `2 |L2|` across the motion on the plane,
  lengthened where the ground is tilted to the plane, so
  `2 |L2| / √(1 − (q · n)²)`, where `q` is the unit vector across the
  motion and `n` the vertical at the central line.

* The Sun's *altitude* is that of the shadow axis,
  `sin h = sin d sin φ + cos d cos φ cos H`, geometric.

### The limits

A *limit* is where the shadow's edge just grazes an observer: at the
moment the observer is nearest the axis, `m = |L2|`. The observers
nearest the axis at a moment lie on the line through the axis across
the shadow's motion `(a, b)`, turned slightly along it as the cone's
radius changes, `u a + v b = L2 L2′` for `(u, v)` the axis less the
observer. On that line the Earth is a chord, every point of which is
on the surface, and the limit is where the chord leaves the shadow:
where the distance from the axis overtakes the cone's radius at that
point's height, found by bisection. The motion and `L2′` depend a
little on where the observer is, so the limit is found again from
where it was. The *northern limit* is to the left of the shadow's
motion, which is always eastward, and the *southern limit* to the
right.

Where the shadow reaches past the end of the chord, the edge of the
path is the horizon: the place on the limb having its greatest
eclipse at sunrise or sunset, the curve NASA's path tables give as
the second limit of an eclipse whose axis misses the Earth. So near
the ends of a path the limits follow the horizon, and they begin
together where the shadow first touches the Earth and end together
where it leaves. The cone's radius changes with the height above the
plane, which changes quickly near the limb, so the shadow first
touches the Earth a little inside the limb, where the chord is
deepest in the shadow. There the ground is so tilted to the shadow
that a hundred metres on the plane is tens of kilometres on the
Earth, so at those two instants the limits are found from the line
straight across the motion at the axis, the same for both, and they
meet.

The limits are those of the umbra of the mean lunar limb, `k2`. The
mountains and valleys of the limb move a limit by a kilometre or two
and are not included, as NASA's path tables do not include them.

### The region of partial eclipse

The partial eclipse is seen wherever the penumbra passes while the
Sun is up. Its region is bounded by:

* The *penumbral limits*, north and south, found as the umbral limits
  are, from the penumbra's radius `L1 = l1 − ζ tan f1`. Where a limit
  would lie beyond the horizon it is left out: the region is bounded
  there by the horizon instead.

* The *sunrise limit*, where the eclipse ends just as the Sun rises,
  and the *sunset limit*, where it begins just as the Sun sets. At a
  moment, the penumbra's edge meets the Earth's limb, `(cos θ,
  ρ1 sin θ)` on the plane, at up to two points, found by Newton's
  method from where a circle of the penumbra's radius meets the unit
  circle. A point where the shadow is leaving, `u a + v b < 0` for
  `(u, v)` the point less the axis, and the ground is turning into
  the day, `ζ′ = −μ′ ξ cos d + d′ η > 0`, sees the eclipse end at
  sunrise; one where the shadow is arriving and the ground turning
  into the night sees it begin at sunset. Places a little inside
  these curves see some of the eclipse with the Sun up.

Within the region, the curves of *maximum eclipse at sunrise* and *at
sunset* are the places having their greatest eclipse on the horizon:
the ends of the chord across the shadow's motion through the axis,
where they are within the penumbra. *First* and *last contact* are
the moments the penumbra first touches the Earth's limb and last
leaves it, at the point of the limb nearest the axis, where the Sun
is on the horizon.

A curve on the horizon can have two branches at the same moment, as
when the penumbra overlaps the limb on one side of the Earth and the
eclipse ends at sunrise both north and south of the axis, so each of
those curves is a list of lines. The horizon is geometric: the
Sun's centre at zero altitude, without refraction.

Because `μ` is the Greenwich hour angle at the moment, longitudes need
no correction for ΔT. NASA's path tables use an ephemeris hour angle
with ΔT applied to it, so they agree when they use the same ΔT.

# `central_point`

```elixir
@type central_point() :: %{
  time: Astro.Time.moment(),
  location: Geo.Point.t(),
  type: :total | :annular,
  width: float(),
  duration: float(),
  sun_altitude: float()
}
```

A point on the central line at a moment: its `t:Geo.Point.t/0`, the
eclipse there, the path's width in kilometres, the duration of
totality or annularity in seconds and the Sun's geometric altitude in
degrees.

# `limit_point`

```elixir
@type limit_point() :: %{time: Astro.Time.moment(), location: Geo.Point.t()}
```

A point on a limit of the path at a moment.

# `line`

```elixir
@type line() :: [limit_point()]
```

A line of points in time order.

# `t`

```elixir
@type t() :: %Astro.Solar.Eclipse.Path{
  central_line: [map()],
  first_contact: map(),
  last_contact: map(),
  maximum_at_sunrise: [[map()]],
  maximum_at_sunset: [[map()]],
  northern_limit: [map()],
  penumbral_northern_limit: [map()],
  penumbral_southern_limit: [map()],
  southern_limit: [map()],
  sunrise_limit: [[map()]],
  sunset_limit: [[map()]],
  type: Astro.Solar.Eclipse.eclipse_type()
}
```

The path of a solar eclipse, as `Astro.solar_eclipse_path/2` returns
it: the eclipse's type; its central line and limits, and its
penumbral limits, as lists of points in time order; its sunrise and
sunset limits and its curves of maximum eclipse at sunrise and
sunset as lists of such lines; and its first and last contact. Each
point's `:time` is a UTC `t:DateTime.t/0`.

# `at`

```elixir
@spec at(Astro.Time.moment()) :: %{
  central_line: central_point() | nil,
  northern_limit: limit_point() | nil,
  southern_limit: limit_point() | nil,
  penumbral_northern_limit: limit_point() | nil,
  penumbral_southern_limit: limit_point() | nil,
  sunrise_limit: [limit_point()],
  sunset_limit: [limit_point()],
  maximum_at_sunrise: [limit_point()],
  maximum_at_sunset: [limit_point()]
}
```

Returns the points of the path of a solar eclipse at a moment.

### Arguments

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

### Returns

* A map with keys `:central_line`, a `t:central_point/0`;
  `:northern_limit`, `:southern_limit`, `:penumbral_northern_limit`
  and `:penumbral_southern_limit`, each a `t:limit_point/0`, `nil`
  where it is not on the Earth at the moment; and `:sunrise_limit`,
  `:sunset_limit`, `:maximum_at_sunrise` and `:maximum_at_sunset`,
  each a list of the up to two `t:limit_point/0`s of the curve at the
  moment.

### Examples

At 18:00 UT on 8 April 2024 the central line of the total eclipse
was over the Pacific, south-west of Mazatlán. NASA's path table, whose ΔT is 1.4 s larger, puts
it at 20°19.2′N 108°45.8′W, about 2 km east. Locations are
`{longitude, latitude}`:

    iex> points = Astro.Solar.Eclipse.Path.at(739_349.75)
    iex> {longitude, latitude} = points.central_line.location.coordinates
    iex> {Float.round(longitude, 2), Float.round(latitude, 2)}
    {-108.78, 20.31}

# `path`

```elixir
@spec path(map(), number()) ::
  {:ok,
   %{
     type: Astro.Solar.Eclipse.eclipse_type(),
     central_line: [central_point()],
     northern_limit: line(),
     southern_limit: line(),
     penumbral_northern_limit: line(),
     penumbral_southern_limit: line(),
     sunrise_limit: [line()],
     sunset_limit: [line()],
     maximum_at_sunrise: [line()],
     maximum_at_sunset: [line()],
     first_contact: limit_point(),
     last_contact: limit_point()
   }}
```

Returns the path of a solar eclipse: its central line and northern
and southern limits, and the bounds of its region of partial eclipse.

The points are at whole multiples of `interval` from midnight, and at
greatest eclipse, while the shadow is on the Earth. Each line also has
a point where it begins and where it ends, found by bisection.

### Arguments

* `eclipse` is a solar eclipse's circumstances as
  `Astro.Solar.Eclipse.eclipse_at_or_after/1` returns them, every
  instant a moment.

* `interval` is the time between points, in days.

### Returns

* `{:ok, path}`, a map of the eclipse's `:type`; its
  `:central_line`, a list of `t:central_point/0`; its
  `:northern_limit`, `:southern_limit`, `:penumbral_northern_limit`
  and `:penumbral_southern_limit`, each a `t:line/0`; its
  `:sunrise_limit`, `:sunset_limit`, `:maximum_at_sunrise` and
  `:maximum_at_sunset`, each a list of `t:line/0`s in the order they
  begin; and its `:first_contact` and `:last_contact`, each a
  `t:limit_point/0`. The central line is empty for an eclipse whose
  shadow axis misses the Earth, and the central line and umbral
  limits are empty for a partial eclipse.

### Examples

    iex> {:ok, eclipse} = Astro.Solar.Eclipse.eclipse_at_or_after(739_300.0)
    iex> {:ok, path} = Astro.Solar.Eclipse.Path.path(eclipse, 1 / 1_440)
    iex> greatest = Enum.max_by(path.central_line, & &1.duration)
    iex> Float.round(greatest.duration, 0)
    268.0

---

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