SPICE References#

Object references in the SPICE kernels are usually represented either by their name (which is not always unique) or by an internal id code. Most of the time, the user does not have to know the reference id and can pass directly its name to the function but it’s not always the case. To provide a simpler access to the SPICE references, the planetary-coverage provides a SpiceRef object that will extract the correct information from the SpicePool.

from planetary_coverage import SpiceRef

For example, for Jupiter barycenter we have:

Note

If the reference is not known, a spiceypy error will be thrown with an additional ValueError:

>>> SpiceRef('FOO')
...
NotFoundError: Spice returns not found for function: bods2c
...
ValueError: Unknown reference: `FOO`
ref = SpiceRef('Jupiter Barycenter')
ref
<SpiceRef> JUPITER BARYCENTER (5)

Generic SpiceRef properties#

This reference can be used either as a string to get its name property:

str(ref)
'JUPITER BARYCENTER'

or as an integer to get its id property:

int(ref)
5

You can compare a SpiceRef with its string and integer values:

ref == 'JUPITER BARYCENTER'
True
ref == 5
True

If a reference frame is available for this object you can use the .frame property to query it:

ref.frame
<SpiceFrame> IAU_JUPITER_BARYCENTER (10_005)

Similarly to the SpicePool, you can query the values from the pool directly on the SpiceRef object:

Warning

By default, the value is not specific to the SpiceRef, any value in the SpicePool is accessible.

ref['BODY599_RADII']
[71492.0, 71492.0, 66854.0]

SpiceBody properties#

If the SpiceRef is a planet or a satellite (like for Ganymede), the SpiceRef is promoted to a SpiceBody.

body = SpiceRef('Ganymede')
body
<SpiceBody> GANYMEDE (503)

For a SpiceBody, you have access to additional attributes. For example, the body radii values:

body.radii  # [km]
[2631.2, 2631.2, 2631.2]

its geometric-mean radius:

body.radius  # [km]
2631.2000000000003

or its centered body-fixed frame:

body.frame
<SpiceFrame> IAU_GANYMEDE (10_025)

For a SpiceBody, the item getter is prefix with BODYXXX_ with XXX being the body code. Therefore you can do:

body['GM']  # Alias to `BODY503_GM`
9887.834453334144

SpiceSpacecraft properties#

If you select a spacecraft reference, it will be promoted to a SpiceSpacecraft:

sc = SpiceRef('JUICE')
sc
<SpiceSpacecraft> JUICE (-28)

SpiceSpacecraft includes a frame and boresight attributes:

sc.frame
<SpiceFrame> JUICE_SPACECRAFT (-28_000)
sc.boresight
array([0, 0, 1])

You can also access the list of the spacecraft instruments available in the SPICE pool:

sc.instruments
[<SpiceInstrument> JUICE_HGA_X (-28_021),
 <SpiceInstrument> JUICE_HGA_KA (-28_022),
 <SpiceInstrument> JUICE_NAVCAM-1 (-28_051),
 <SpiceInstrument> JUICE_NAVCAM-2 (-28_052),
 <SpiceInstrument> JUICE_STR-OH1 (-28_061),
 <SpiceInstrument> JUICE_STR-OH2 (-28_062),
 <SpiceInstrument> JUICE_STR-OH3 (-28_063),
 <SpiceInstrument> JUICE_SCHULTE_KA_BAND (-28_075),
 <SpiceInstrument> JUICE_SCHULTE_X_BAND (-28_076),
 <SpiceInstrument> JUICE_JMC-1 (-28_081),
 <SpiceInstrument> JUICE_JMC-2 (-28_082),
 <SpiceInstrument> JUICE_GALA_TXL_MAIN (-28_111),
 <SpiceInstrument> JUICE_GALA_TXL_RED (-28_112),
 <SpiceInstrument> JUICE_GALA_RXT (-28_120),
 <SpiceInstrument> JUICE_JANUS (-28_200),
 <SpiceInstrument> JUICE_MAJIS_VISNIR (-28_410),
 <SpiceInstrument> JUICE_MAJIS_VISNIR_B2 (-28_412),
 <SpiceInstrument> JUICE_MAJIS_VISNIR_B4 (-28_414),
 <SpiceInstrument> JUICE_MAJIS_IR (-28_420),
 <SpiceInstrument> JUICE_MAJIS_IR_B2 (-28_422),
 <SpiceInstrument> JUICE_MAJIS_IR_B4 (-28_424),
 <SpiceInstrument> JUICE_MAJIS_RAD (-28_430),
 <SpiceInstrument> JUICE_MAJIS_ENVELOPE (-28_440),
 <SpiceInstrument> JUICE_PEP_JDC (-28_510),
 <SpiceInstrument> JUICE_PEP_JNA (-28_520),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S0 (-28_532),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S1 (-28_533),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S2 (-28_534),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S3 (-28_535),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S4 (-28_536),
 <SpiceInstrument> JUICE_PEP_NIM_NEUION_S5 (-28_537),
 <SpiceInstrument> JUICE_PEP_NIM_THERMAL-1 (-28_538),
 <SpiceInstrument> JUICE_PEP_NIM_THERMAL-2 (-28_539),
 <SpiceInstrument> JUICE_PEP_JEI (-28_540),
 <SpiceInstrument> JUICE_PEP_JOEE_S1 (-28_551),
 <SpiceInstrument> JUICE_PEP_JOEE_S2 (-28_552),
 <SpiceInstrument> JUICE_PEP_JENI (-28_560),
 <SpiceInstrument> JUICE_PEP_JENI_PY (-28_561),
 <SpiceInstrument> JUICE_PEP_JENI_MY (-28_562),
 <SpiceInstrument> JUICE_RIME_BASE (-28_600),
 <SpiceInstrument> JUICE_RIME+X (-28_601),
 <SpiceInstrument> JUICE_SWI_FULL (-28_800),
 <SpiceInstrument> JUICE_SWI_FULL_GCO500 (-28_801),
 <SpiceInstrument> JUICE_SWI_CH1 (-28_810),
 <SpiceInstrument> JUICE_SWI_CH2 (-28_820),
 <SpiceInstrument> JUICE_UVS_AP_HP (-28_860),
 <SpiceInstrument> JUICE_UVS_SP (-28_870),
 <SpiceInstrument> JUICE_RADEM_ESD (-28_921),
 <SpiceInstrument> JUICE_RADEM_PSD (-28_922),
 <SpiceInstrument> JUICE_RADEM_HISD (-28_923)]

or select a single one:

inst = sc.instr('JANUS')
inst
<SpiceInstrument> JUICE_JANUS (-28_200)

SpiceInstrument properties#

When an instrument is selected (as a SpiceInstrument), you can get its field of view parameters:

inst.boresight
array([0., 0., 1.])
inst.bounds
array([[-0.01500832,  0.01125587,  0.99982401],
       [-0.01500832, -0.01125587,  0.99982401],
       [ 0.01500832, -0.01125587,  0.99982401],
       [ 0.01500832,  0.01125587,  0.99982401]])
inst.shape
'RECTANGLE'
inst.frame
<SpiceFrame> JUICE_JANUS (-28_200)

You can also retrieve the detector size:

inst.ns, inst.nl
(1504, 2000)

or the full field-of-view along the track and cross track:

inst.fov_along_track, inst.fov_cross_track  # in radians
(0.022514747350726852, 0.030019663134302467)

Caution

We assume that the sample direction is aligned with the cross-track direction (ie. 1-line acquisition in push-broom mode should be in the direction of flight).

This convention is not strictly enforced in the instrument kernel and the user must be careful and adjust theses values according to the detector orientation relative to the spacecraft motion.

Warning

JUICE_JANUS instrument in v06 does not follow this convention. We manually manage this exception for the moment (see MR !27 for more details).

as well as the pixel instantaneous field-of-view:

inst.ifov_along_track, inst.ifov_cross_track  # in radians
(1.4969911802344982e-05, 1.5009831567151233e-05)

For a SpiceInstrument, the item getter is prefix with INSXXX_ with XXX being the instrument code. Therefore you can do:

inst['PIXEL_SAMPLES']  # Alias to `INS-28200_PIXEL_SAMPLES`
1504.0

You can display the boresight, the bounds vectors and rays of the field of view contour in the instrument frame:

inst.display();
../_images/997f1eb79b60cd5cb064f23c3809a94e5811d64dd6cf1e89f436bdeee9b6e69c.png

Or you can represent it in the plane orthogonal to the field of view:

inst.view();
../_images/2353200fa6f33ffe87c2d05143e9d2d60f652f6bf970e6cb72b8b7942c03df07.png

SpiceFrame properties#

If the SpiceRef is a SPICE frame, the SpiceRef is promoted to a SpiceFrame:

frame = SpiceRef('JUICE_SPACECRAFT_PLAN')
frame
<SpiceFrame> JUICE_SPACECRAFT_PLAN (-28_001)

You can retrieve the type of frame:

frame.class_type
'CK frame'

The frame body center:

frame.center
<SpiceFrame> JUICE_SPACECRAFT (-28_000)

and when available, the associated sclk and spk:

frame.sclk
<SpiceFrame> JUPITER_SYSTEM3RH_1965 (-28_999)
frame.spk
<SpiceSpacecraft> JUICE (-28)

Danger

SPICE codes can overlap SPICE frame ids. For example here, both MERCURY_BARYCENTER and J2000 frame have an id of 1. It is recommend to be very carefull with theses cases and use explicit names:

SpiceRef('MERCURY_BARYCENTER')
<SpiceRef> MERCURY BARYCENTER (1)
SpiceRef('J2000')
<SpiceFrame> J2000 (1)

Planetocentric vs. planetocentric coordinates#

Recommended reading: NAIF reference frames and coordinates system

Planetocentric coordinates#

NAIF definition:

For planets and their satellites the +Z axis (+90 latitude) always points to the north side of the invariable plane (the plane whose normal vector is the angular momentum vector of the solar system):

  • Planetocentric longitude increases positively eastward (-180° to +180°)

  • Planetocentric latitude increases positively northward (-90° to +90°)

NAIF planetocentric coordinates

Note

In the planetary-coverage, the planetocentric longitudes are defined as strictly positive eastward ([0°, 360°[).

Planetographic coordinates#

NAIF definition:

For planet and satellite planetographic coordinate systems:

  • Planetographic longitude is usually defined such that the sub-observer longitude increases with time as seen by a distant, fixed observer (0° to 360°)

  • The Earth, Moon and Sun are exceptions; planetographic longitude is positive east by default (0° to 360°)

  • Planetographic latitude is planetodetic latitude (-90° to +90°), ie. is tied to a reference ellipsoid and for a point, P, on a reference ellipsoid, the angle measured from the X-Y plane to the surface normal at the point of interest. For points not on the ellipsoid, equals latitude at the nearest point on the reference ellipsoid and increases positively northward.

NAIF planetographic coordinates

Planetographic to Planetocentric coordinates.#

Warning

Depending on the body, the output will be either in east or in west longitude.

It is possible to convert planetographic coordinates to planetographic coordinates with the ocentric2ographic() function:

Note

This calculation requires that a tpc kernel is loaded into the SPICE pool.

from planetary_coverage.spice import ocentric2ographic

lon_w, lat = ocentric2ographic('MARS', 90, 45)  # east longitude, latitude

lon_w, lat  # west longitudes for MARS
(270.0, 45.33789641791753)