# `Astro.Ephemeris.Subset`
[🔗](https://github.com/kipcole9/astro/blob/v2.5.0/lib/astro/ephemeris/subset.ex#L1)

Extracts a smaller DAF/SPK ephemeris kernel from a larger one.

JPL's `de440s.bsp` is ~31 MB because it carries all planetary
barycenters over 1849–2150. `Astro` uses only four segments — Moon
and Earth relative to the Earth–Moon Barycenter, and Sun and EMB
relative to the Solar System Barycenter — so the remainder can be
discarded.

Extraction is **lossless** within the retained window: the original
Chebyshev coefficients are copied verbatim, so positions computed
from a subset file are bit-for-bit identical to those computed from
the source file. No refitting is performed.

### What drives the file size

Body selection alone saves less than expected. The Moon and Earth
segments are the two largest in the file (degree-12 polynomials on
4-day intervals), together ~17 MB, while the eight discarded
planetary barycenters use 32-day intervals and cost little. The
dominant lever is the **time window** — after body selection the
cost is roughly 42 KB per year of coverage.

A second saving comes from omitting the Earth→EMB segment. By the
definition of the barycenter it is an exact scalar multiple of the
Moon→EMB segment:

    Earth→EMB = -(1 / EMRAT) x Moon→EMB

where `EMRAT` is the Earth/Moon mass ratio (81.3005682214972154 for
DE440). `Astro.Ephemeris.Kernel` reconstructs the segment on demand
when it is absent, so omitting it halves the payload at a cost of
one multiplication per evaluation.

### Compatibility

The output is a valid DAF/SPK file. The source file record is copied
intact — preserving the format identifier, the FTP validation string
and the binary format marker — so the result is readable by other
SPICE implementations (CSPICE, `jplephem`, Astropy) and not only by
this library.

# `default_bodies`

```elixir
@spec default_bodies() :: [{integer(), integer()}]
```

Returns the default set of `{target_id, centre_id}` pairs retained by
`extract/3`.

Earth→EMB (399→3) is deliberately absent; it is reconstructed from
Moon→EMB at runtime. See the module documentation.

### Returns

* A list of `{target_id, centre_id}` tuples.

### Examples

    iex> Astro.Ephemeris.Subset.default_bodies()
    [{301, 3}, {10, 0}, {3, 0}]

# `extract`

```elixir
@spec extract(Path.t(), Path.t(), keyword()) :: {:ok, map()} | {:error, term()}
```

Extracts selected segments and a time window from a DAF/SPK file.

### Arguments

* `source_path` is the path of the DAF/SPK file to read, typically a
  JPL `de440s.bsp`.

* `dest_path` is the path of the subset file to write.

### Options

* `:bodies` is a list of `{target_id, centre_id}` NAIF body ID pairs
  to retain. Defaults to the four segments `Astro` requires,
  excluding Earth→EMB, which is reconstructed at runtime.

* `:from` is the first instant the subset must cover, as a `Date`,
  `DateTime` or integer year. Defaults to the source file's start.

* `:to` is the last instant the subset must cover, in the same forms
  as `:from`. Defaults to the source file's end.

### Returns

* `{:ok, report}` where `report` is a map containing `:path`,
  `:bytes`, `:segments` (a list of retained `{target, centre}`
  pairs) and `:coverage` (a `{first_year, last_year}` tuple).

* `{:error, reason}` if the source cannot be read or parsed, or if a
  requested body pair or time window is not present in the source.

### Examples

    # Retain Astro's segments over 1900-2100
    Astro.Ephemeris.Subset.extract(
      "de440s.bsp",
      "priv/de440s-astro.bsp",
      from: 1900,
      to: 2100
    )

---

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