Python package for NAIF WebGeoCalc API

In december 2018, JPL/NAIF announced an experimental API RESTful interface for their new WebGeocalc server (which make online SPICE calculations). Documentation and JavaScript examples are already available.

This package is an early attempt to provide a Python interface to make SPICE calculation through this API.

Disclaimer

This project is not supported or endorsed by either JPL, NAIF or NASA. The code is provided "as is", use at your own risk.

Use WebGeoCalc API

In [1]:
from webgeocalc import API

API.url
Out[1]:
'https://wgc2.jpl.nasa.gov:8443/webgeocalc/api'

The default API endpoint can be defined with the WGC_URL global environment variable. If it is not present, the API will fallback to the JPL endpoint.

You can also use the ESA webgeocalc server:

In [2]:
from webgeocalc import ESA_API

ESA_API.url
Out[2]:
'http://spice.esac.esa.int/webgeocalc/api'

Get kernel sets

In [3]:
kernel_sets = API.kernel_sets() # /kernel-sets
kernel_sets
Out[3]:
[<KernelSetDetails> Solar System Kernels (id: 1),
 <KernelSetDetails> Latest Leapseconds Kernel (id: 2),
...
 <KernelSetDetails> Ground Stations Kernels (id: 4),
...
 <KernelSetDetails> SPICE Class -- Binary PCK Lesson Kernels (Earth) (id: 39)]

Kernel set object

In [4]:
kernel_set = kernel_sets[0]
int(kernel_set) # kernelSetId
Out[4]:
1
In [5]:
str(kernel_set) # Caption
Out[5]:
'Solar System Kernels'
In [6]:
kernel_set.description # Get kernel attribute
Out[6]:
'Generic kernels for planets, satellites, and some asteroids covering from 1950-01-01 to 2050-01-01.'
In [7]:
kernel_set.keys()
Out[7]:
dict_keys(['caption', 'sclkId', 'description', 'kernelSetId', 'missionId'])
In [8]:
kernel_set.values()
Out[8]:
dict_values(['Solar System Kernels', '0', 'Generic kernels for planets, satellites, and some asteroids covering from 1950-01-01 to 2050-01-01.', '1', 'gen'])
In [9]:
dict(kernel_set.items())
Out[9]:
{'caption': 'Solar System Kernels',
 'sclkId': '0',
 'description': 'Generic kernels for planets, satellites, and some asteroids covering from 1950-01-01 to 2050-01-01.',
 'kernelSetId': '1',
 'missionId': 'gen'}

Get a kernel set by it's id or caption name:

In [10]:
# By ID
API.kernel_set(1)
Out[10]:
<KernelSetDetails> Solar System Kernels (id: 1)
In [11]:
# By full caption name
API.kernel_set('Solar System Kernels')
Out[11]:
<KernelSetDetails> Solar System Kernels (id: 1)
In [12]:
# Not case sensitive
API.kernel_set('solar system kernels')
Out[12]:
<KernelSetDetails> Solar System Kernels (id: 1)
In [13]:
# Search by partial name
API.kernel_set('Solar')
Out[13]:
<KernelSetDetails> Solar System Kernels (id: 1)

Handling errors:

In [14]:
from webgeocalc.errors import TooManyKernelSets, KernelSetNotFound

# More than one kernel found
try:
    API.kernel_set('Cassini')
except TooManyKernelSets as err:
    print(err)
Too many kernel sets contains 'Cassini' in their names:
 - Cassini Huygens
 - SPICE Class -- CASSINI Remote Sensing Lesson Kernels
In [15]:
# Kernel not found
try:
    API.kernel_set('Missing kernel')
except KernelSetNotFound as err:
    print(err)
Kernel set 'Missing kernel' not found

Get bodies

In [16]:
bodies = API.bodies(5) # /kernel-set/{kernelSetId}/bodies
# or
API.bodies('Cassini Huygens')
Out[16]:
[<BodyData> CASSINI (id: -82),
 <BodyData> CAS (id: -82),
...
 <BodyData> SOLAR SYSTEM BARYCENTER (id: 0)]
In [17]:
body = bodies[0]
print(f"Body `id`: {int(body)} and `name`: {str(body)}")
Body `id`: -82 and `name`: CASSINI

Get frames

In [18]:
frames = API.frames(5) # /kernel-set/{kernelSetId}/frames
# or
API.frames('Cassini Huygens')
Out[18]:
[<FrameData> CASSINI_SATURN_SKR4N_LOCK (id: -82982),
...
 <FrameData> IAU_TITAN (id: 10044),
...
 <FrameData> ITRF93 (id: 13000)]
In [19]:
frames[58].items()
Out[19]:
dict_items([('id', -82905), ('name', 'CASSINI_KSO'), ('centerBodyID', 699), ('frameClass', 5)])

Get Instruments

In [20]:
instruments = API.instruments(5) # /kernel-set/{kernelSetId}/intruments
# or
API.instruments('Cassini Huygens')
Out[20]:
[<InstrumentData> CASSINI_CIRS_RAD (id: -82898),
...
 <InstrumentData> CASSINI_ISS_NAC (id: -82360),
...
 <InstrumentData> CASSINI_SRU-A (id: -82001)]
In [21]:
print(f"Body `id`: {int(instruments[0])} and `name`: {str(instruments[0])}")
Body `id`: -82898 and `name`: CASSINI_CIRS_RAD