Skip to content

Draft: Kernels dir placeholder

Benoit Seignovert requested to merge kernels-dir-placeholder into main

New Kernel object

>>> from planetary_coverage import Kernel

>>> Kernel('naif0012.tls')
<Kernel> naif0012.tls (⏱️ LSK | 5 kB)

>>> Kernel('naif0012.tls').exists()
True

>>> Kernel('naif0012.tls').file_size
'5 kB'

>>> Kernel('naif0012.tls').checksum
'25a2fff30b0dedb4d76c06727b1895b1'

It supports placeholders (by default: $KERNELS) for kernel directory:

>>> Kernel('$KERNELS/lsk/naif0012.tls', kernels_dir='kernels/')
<Kernel> kernels/lsk/naif0012.tls (⏱️ LSK | 5 kB)

# Full resolved path
>>> Kernel('$KERNELS/lsk/naif0012.tls', kernels_dir='/data/kernels/').path
'/data/kernels/lsk/naif0012.tls'

and remote location (with .url property):

>>> Kernel('$KERNELS/lsk/naif0012.tls', remote='https://example.org').url
'https://example.org/lsk/naif0012.tls'

Direct download is available (if a remote is provided):

>>> Kernel('$KERNELS/lsk/naif0012.tls', kernels_dir='kernels/', remote='https://example.org').download()
[Download] https://example.org/lsk/naif0012.tls
# or
>>> Kernel('$KERNELS/lsk/naif0012.tls', kernels_dir='kernels/').downlaod(remote='https://example.org')
[Download] https://example.org/lsk/naif0012.tls

Note: The download is silently skipped if the file is already present locally. Use force=True to overwrite the existing file.

Support custom placeholders:

>>> Kernel('$CUSTOM/naif0012.tls', kernels_dir={'$CUSTOM': 'kernels/lsk'})
<Kernel> kernels/lsk/naif0012.tls (⏱️ LSK | 5 kB)

>>> REMOTE_JUICE = {
  'data': 'https://spiftp.esac.esa.int/data/SPICE/',
  'mission': 'JUICE',
}
>>> Kernel('$DATA/$MISSION/kernels/pck/pck00010.tpc', remote=REMOTE_JUICE).url
'https://spiftp.esac.esa.int/data/SPICE/JUICE/kernels/pck/pck00010.tpc'

For text kernels, the content of the file is loaded in .content:

>>> kernel.content
"""KPL/LSK


LEAPSECONDS KERNEL FILE
===========================================================================

Modifications:
--------------
...

"""

and the data are parsed in:

>>> dict(kernel)
{'DELTET/DELTA_T_A': 32.184,
 'DELTET/K': 0.001657,
 'DELTET/EB': 0.01671,
 'DELTET/M': [6.239996, 1.99096871e-07],
 ...
}

It can also be queried as a dict for specific keys:

>>> kernel['DELTET/DELTA_T_A']
32.184

New KernelsList object

>>> from planetary_coverage import KernelsList

>>> KernelsList('naif0012.tls', 'pck00010.tpc')
<KernelsList> 2 kernels:
 - <Kernel> naif0012.tls (⏱️ LSK | 5 kB)
 - <Kernel> pck00010.tpc (🪐 PCK | 123 kB)

It also support kernels_dir and remote placeholders:

>>> kernels = KernelsList(
  '$KERNELS/lsk/naif0012.tls',
  '$KERNELS/pck/pck00010.tpc',
  kernels_dir='kernels/',
  remote='https://naif.jpl.nasa.gov/pub/naif/generic_kernels/',
)

These properties will be applied to all Kernel children:

>>> kernels.url
['https://naif.jpl.nasa.gov/pub/naif/generic_kernels/lsk/naif0012.tls',
 'https://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/pck00010.tpc']

When requested, the kernel will be downloaded in parallel (only on Unix system, see #80 (closed) for Windows):

>>> kernels.download()
[Download] https://example.org/lsk/naif0012.tls
[Download] https://example.org/pck/pck00010.tpc

Both, Kernel and KernelsList are fully compatibible with spiceypy.furnsh function to load the kernels in the spice pool:

>>> Kernel('pck00010.tpc').load(purge=True)

>>> from planetary_coverage import SpicePool

>>> SpicePool.kernels
('/path/to/pck00010.tpc',)

>>> KernelsList(
    '$KERNELS/lsk/naif0012.tls',
    '$KERNELS/pck/pck00010.tpc',
    kernels_dir='/data/kernels/',
    load=True,
    purge=True,
)

>>> SpicePool.kernels
('/data/kernels/lsk/naif0012.tls',
 '/data/kernels/pck/pck00010.tpc')

Or explicitly only with spiceypy:

>>> import spiceypy as sp

>>> sp.kclear()  # Purge the SPICE pool
>>> sp.furnsh(Kernel('naif0012.tls'))
>>> sp.ktotal('ALL')
1

>>> sp.kclear()  # Purge the SPICE pool
>>> sp.furnsh(KernelsList('$KERNELS/lsk/naif0012.tls', '$KERNELS/pck/pck00010.tpc', kernels_dir='kernels/'))
>>> sp.ktotal('ALL')
2

Remote key url

New SPICE archives URL locations:

from planetary_coverage.spice import SPICE_ARCHIVES

>>> SPICE_ARCHIVES
{'NASA': 'https://naif.jpl.nasa.gov/pub/naif',
 'ESA': 'https://spiftp.esac.esa.int/data/SPICE',
 'JAXA': 'https://data.darts.isas.jaxa.jp/pub/spice'}

New spice.get_remote_url() helper to locate space mission SPICE kernels archive

>>> from planetary_coverage.spice import get_remote_url

>>> get_remote_url('@NASA')
'https://naif.jpl.nasa.gov/pub/naif/generic_kernels/'

>>> get_remote_url('@ESA')
'https://spiftp.esac.esa.int/data/SPICE/esa_generic/kernels'

>>> get_remote_url('@NASA/CASSINI')
'https://naif.jpl.nasa.gov/pub/naif/CASSINI/kernels'

The key can be either @SPACE_AGENCY or @SPACE_AGENCY/MISSION_NAME. Space and lowercase are accepted most of the time for ESA missions but NASA missions must be uppercased.

Theses keys also works on Kernel and KernelsList remote keyword:

>>> Kernel('lsk/naif0012.tls', remote='@NASA').url
'https://naif.jpl.nasa.gov/pub/naif/generic_kernels/lsk/naif0012.tls'
  • New metakernel formatter:
>>> from planetary_coverage.spice import format_metakernel

>>> format_metakernel(
        {
            'PATH_VALUES': ['.'],
            'PATH_SYMBOLS': ['KERNELS'],
            'KERNELS_TO_LOAD': [
                '$KERNELS/naif0012.tls',
                '$KERNELS/pck00011.tpc',
            ],
            'SKD_VERSION': 'v999_20240807_001',
        },
        header='Header\n======\n\nDescription.',
        footer='End of the File.',
    )
"""KPL/MK

Header
======

Description.

\begindata

PATH_VALUES     = ( '.' )
PATH_SYMBOLS    = ( 'KERNELS' )
KERNELS_TO_LOAD = ( '$KERNELS/naif0012.tls',
                    '$KERNELS/pck00011.tpc'  )
SKD_VERSION     = 'v999_20240807_001'

\begintext

End of the File.
"""

The content of the data is validated to ensure that KERNELS_TO_LOAD is present and the symbols are consistent between KERNELS_TO_LOAD and PATH_SYMBOLS.

Documentation

The SPICE kernel documentation section was updated to reflect theses changes and add more examples on Kernel and KernelsList.

Changed

  • Change ENVISION key in ESA_MK from 'EnVision' to 'ENVISION'
  • misc.wget now supports parallel downloads when multiple URLs are provided (only on Unix system, see #80 (closed) for Windows).
  • Move kernel_parser(), get_data(), extract_data(), concatenate(), parse(), read(), format_data(), format_value(), chunk_string() from spice.kernel to spice.parser submodules.
  • Move get_item(), find_item(), get_ktype(), get_summary() and get_details() from spice.kernel to spice.misc submodules
  • @depreciated decorator now also works on functions.

Fixes

  • Kernel data parser now supports dash in keys.
  • Kernel data parser now supports \begindata token in text sections.

Depreciations

  • Depreciate kernel_parser() in favor of the new Kernel object
  • Depreciate planetary_coverage.spice.kernel.get_type() in favor of planetary_coverage.spice.misc.get_ktype()
  • Depreciate DepreciationHelper in favor of Depreciated

Closes #75, #84 and #88.

Edited by Benoit Seignovert

Merge request reports