Skip to content

Commit 65a887e

Browse files
Docs: describe how to load >1 ephemeris file #145
And, improve the exception raised if a deflector is missing.
1 parent 4cf5f5d commit 65a887e

File tree

2 files changed

+108
-15
lines changed

2 files changed

+108
-15
lines changed

documentation/planets.rst

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ for any body that an ephemeris links to target zero,
199199
the Solar System barycenter.
200200
For example,
201201
DE421 — as you can see above —
202-
provides a segment directly linking the Solar System barycenter
203-
with the Sun:
202+
provides a segment directly linking the Sun
203+
to the Solar System barycenter:
204204

205205
.. testcode::
206206

@@ -211,11 +211,10 @@ with the Sun:
211211

212212
'de421.bsp' segment 0 SOLAR SYSTEM BARYCENTER -> 10 SUN
213213

214-
By contrast,
215-
generating a position for the Moon with DE421
216-
requires Skyfield to add together two segments behind the scenes.
217-
The first segment provides the position of the Earth-Moon center of gravity,
218-
while the second segment provides the offset from there to the Moon.
214+
Linking the Moon to the Solar System barycenter with DE421
215+
requires two segments,
216+
one providing the vector to the Earth-Moon system’s center of gravity,
217+
and the second providing the vector from there to the Moon.
219218

220219
.. testcode::
221220

@@ -228,18 +227,91 @@ while the second segment provides the offset from there to the Moon.
228227
'de421.bsp' segment 0 SOLAR SYSTEM BARYCENTER -> 3 EARTH BARYCENTER
229228
'de421.bsp' segment 3 EARTH BARYCENTER -> 301 MOON
230229

230+
Each time you ask this ``moon`` object for a position,
231+
it computes both vectors and adds them together for you.
232+
231233
Note that most planets are so massive compared to their moons
232234
that you can ignore the difference
233235
between the planet and its system barycenter.
234236
If you want to observe Mars or Jupiter from elsewhere in the Solar System,
235237
just ask for the ``Mars Barycenter``
236-
or ``Jupiter Barycenter`` position instead.
237-
The Earth-Moon system is unusual
238-
for featuring a satellite with so much mass —
239-
though even in that case,
240-
their common barycenter is always inside the Earth.
241-
Only Pluto has a satellite so massive and so distant
242-
that the Pluto-Charon barycenter is in space between them.
238+
or ``Jupiter Barycenter``.
239+
Only the Earth and Pluto have such massive moons
240+
that their system barycenters are poor approximations
241+
for the position of the planets themselves.
242+
243+
Loading several ephemeris files
244+
===============================
245+
246+
You may sometimes need to load segments
247+
from several different ephemeris files at once.
248+
For example,
249+
if you load ``jup310.bsp`` for its support of Jupiter’s moons,
250+
you will find that it doesn’t include most of the other planets.
251+
This means that you will get an error
252+
if you try to compute an apparent position,
253+
because Skyfield —
254+
wanting to provide its usual high precision —
255+
will try to compute how much the position is deflected
256+
by the gravity of the Sun, Jupiter, and Saturn,
257+
but Saturn is missing from ``jup310.bsp``.
258+
259+
.. testcode::
260+
261+
jup310 = load('jup310.bsp')
262+
ganymede = jup310['Ganymede']
263+
264+
a = ganymede.at(t).observe(earth).apparent()
265+
266+
.. testoutput::
267+
268+
Traceback (most recent call last):
269+
...
270+
ValueError: ephemeris is missing '6 SATURN BARYCENTER'...
271+
272+
If you simply don’t need the extra accuracy
273+
that is provided by accounting for deflection,
274+
you can turn deflection off
275+
by replacing the default tuple of deflectors ``(10, 599, 699)``
276+
(which means Sun, Jupiter, Saturn)
277+
with an empty tuple:
278+
279+
.. testcode::
280+
281+
no_deflectors = ()
282+
a = ganymede.at(t).observe(earth).apparent(no_deflectors)
283+
284+
Or, you can leave deflection turned on,
285+
and supplement your in-memory ephemeris object
286+
with additional segments
287+
loaded from another ephemeris file.
288+
Since the ``.segments`` attribute of an ephemeris object
289+
is simply a Python list,
290+
you can ``.extend()`` it with further segments:
291+
292+
.. testcode::
293+
294+
before = len(jup310.segments)
295+
296+
de421 = load('de421.bsp')
297+
jup310.segments.extend(de421.segments)
298+
299+
after = len(jup310.segments)
300+
print('Expanded ephemeris from {} to {} segments'
301+
.format(before, after))
302+
303+
a = ganymede.at(t).observe(earth).apparent()
304+
305+
.. testoutput::
306+
307+
Expanded ephemeris from 13 to 28 segments
308+
309+
Note that extending the segment list
310+
does not make any change to your files on disk;
311+
the files ``de421.bsp`` and ``jup310.bsp`` are left unmodified.
312+
Instead, the ``.extend()`` maneuver
313+
simply collects the segments together in memory
314+
where a single Python ephemeris object can see them.
243315

244316
.. _Making an ephemeris excerpt:
245317

skyfield/positionlib.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# -*- coding: utf-8 -*-
22
"""Classes representing different kinds of astronomical position."""
33

4+
from jplephem.names import target_names as target_names
45
from numpy import array, cos, einsum, full, reshape, nan, nan_to_num, zeros
6+
57
from . import framelib
68
from .constants import ANGVEL, AU_M, C, C_AUDAY, ERAD, DAY_S, RAD2DEG, pi, tau
79
from .descriptorlib import reify
@@ -771,7 +773,14 @@ def apparent(self, deflectors=(10, 599, 699)):
771773
rmass = rmasses[code]
772774
if (code % 100 == 99) and (code not in self._ephemeris):
773775
code //= 100
774-
deflector = self._ephemeris[code]
776+
try:
777+
deflector = self._ephemeris[code]
778+
except KeyError:
779+
m = _deflector_message.format(code, target_names[code])
780+
e = ValueError(m)
781+
e.__cause__ = None
782+
e.target = code
783+
raise e
775784
deflector_au = _compute_deflector_position(
776785
t, bcrs_position, target_au, deflector, tlt,
777786
)
@@ -795,6 +804,18 @@ def apparent(self, deflectors=(10, 599, 699)):
795804
apparent._observer_gcrs_au = observer_gcrs_au
796805
return apparent
797806

807+
_deflector_message = """\
808+
ephemeris is missing '{0} {1}'
809+
810+
By default, apparent() computes how the target's light is deflected by
811+
the gravity of the Sun, Jupiter, and Saturn. Either add the missing
812+
body to your ephemeris, or adjust your call to apparent() like this:
813+
814+
position.apparent(deflectors=(10, 599)) # only Sun and Jupiter
815+
position.apparent(deflectors=()) # turn deflection off
816+
817+
"""
818+
798819
class Apparent(ICRF):
799820
"""An apparent |xyz| position relative to a particular observer.
800821

0 commit comments

Comments
 (0)