Source code for junocam_projection.spice_utils

import os
import glob
from bs4 import BeautifulSoup
import requests
import re
import fnmatch
import tqdm

BASEURL = "https://naif.jpl.nasa.gov/pub/naif/JUNO/kernels/"


[docs] def fetch_kernels_from_https(path: str, pattern: str) -> list[str]: """Fetch kernels from URL matching a given pattern :param path: URL at which to search for kernels (will parse HTML links in this URL) :param pattern: file-name pattern to search for relevant links :return: list of files that match the given pattern """ with requests.get(path) as response: soup = BeautifulSoup(response.text, "html.parser") kernels_all = [a["href"] for a in soup.find("pre").find_all("a")] files = fnmatch.filter(kernels_all, pattern) basefolder = os.path.split(os.path.normpath(path))[-1] return [os.path.join(basefolder, file) for file in files]
[docs] def fetch_kernels_from_disk(path: str, pattern: str) -> list[str]: """Fetch kernels from local path matching a given pattern :param path: path to the folder at which to search for kernels :param pattern: file-name pattern to search for relevant links :return: list of files that match the given pattern """ return [ file.replace(path, "") for file in sorted(glob.glob(os.path.join(path, pattern))) ]
[docs] def check_and_download_kernels(kernels: list[str], KERNEL_DATAFOLDER: str) -> list[str]: """Check whether the list of kernels are in the local directory and download them if needed. :param kernels: list of kernel filenames (relative to the root URL) :param KERNEL_DATAFOLDER: path to the local kernel directory to store downloaded kernels :return: list of local paths to the kernels """ kernel_fnames = [] for kernel in kernels: if not os.path.exists(os.path.join(KERNEL_DATAFOLDER, kernel)): download_kernel(kernel, KERNEL_DATAFOLDER) kernel_fnames.append(os.path.join(KERNEL_DATAFOLDER, kernel)) return kernel_fnames
[docs] def download_kernel(kernel: str, KERNEL_DATAFOLDER: str) -> None: """Download a given kernel to the local folder :param kernel: URL path to the kernel :param KERNEL_DATAFOLDER: root folder to store the downloaded kernel """ link = os.path.join(BASEURL, kernel) file_name = os.path.join(KERNEL_DATAFOLDER, kernel) with open(file_name, "wb") as f: print("Downloading %s" % file_name) response = requests.get(link, stream=True) total_length = response.headers.get("content-length") if total_length is None: # no content length header f.write(response.content) else: total_length = int(total_length) with tqdm.tqdm( total=total_length, unit="B", unit_scale=True, dynamic_ncols=True, unit_divisor=1024, ascii=True, desc=f"Downloading {kernel}", ) as pbar: for data in tqdm.tqdm(response.iter_content(chunk_size=4096)): f.write(data) pbar.update(len(data))
[docs] def get_kernels( KERNEL_DATAFOLDER: str, start_utc: float, offline: bool = False ) -> list[str]: """Fetch all relevant kernels for JunoCam at a given time :param KERNEL_DATAFOLDER: path to the local kernel directory to store downloaded kernels :param start_utc: the spacecraft clock time in start_utc :param offline: use the kernels stored locally (saves time by not scraping the NAIF servers) :return: list of local paths to the kernels """ if not os.path.exists(KERNEL_DATAFOLDER): os.mkdir(KERNEL_DATAFOLDER) for folder in ["ik", "ck", "spk", "pck", "fk", "lsk", "sclk"]: if not os.path.exists(os.path.join(KERNEL_DATAFOLDER, folder)): os.mkdir(os.path.join(KERNEL_DATAFOLDER, folder)) if offline: print("Fetching kernels from disk") iks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "ik/juno_junocam_v*.ti") cks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "ck/juno_sc_*.bc") spks1 = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "spk/spk_*.bsp") spks2 = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "spk/jup*.bsp") spks3 = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "spk/de*.bsp") spks4 = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "spk/juno_struct*.bsp") pcks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "pck/pck*.tpc") fks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "fk/juno_v*.tf") sclks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "sclk/JNO_SCLKSCET.*.tsc") lsks = fetch_kernels_from_disk(KERNEL_DATAFOLDER, "lsk/naif*.tls") else: print("Fetching kernels from NAIF server") iks = fetch_kernels_from_https(BASEURL + "ik/", "juno_junocam_v*.ti") cks = fetch_kernels_from_https(BASEURL + "ck/", "juno_sc_*.bc") spks1 = fetch_kernels_from_https(BASEURL + "spk/", "spk_*.bsp") spks2 = fetch_kernels_from_https(BASEURL + "spk/", "jup*.bsp") spks3 = fetch_kernels_from_https(BASEURL + "spk/", "de*.bsp") spks4 = fetch_kernels_from_https(BASEURL + "spk/", "juno_struct*.bsp") pcks = fetch_kernels_from_https(BASEURL + "pck/", "pck*.tpc") fks = fetch_kernels_from_https(BASEURL + "fk/", "juno_v*.tf") sclks = fetch_kernels_from_https(BASEURL + "sclk/", "JNO_SCLKSCET.*.tsc") lsks = fetch_kernels_from_https(BASEURL + "lsk/", "naif*.tls") year, month, day = start_utc.split("-") yy = year[2:] mm = month dd = day[:2] intdate = int("%s%s%s" % (yy, mm, dd)) kernels = [] # find the ck and spk kernels for the given date ckpattern = r"juno_sc_rec_([0-9]{6})_([0-9]{6})\S*" nck = 0 for ck in cks: fname = os.path.basename(ck) groups = re.findall(ckpattern, fname) if len(groups) == 0: continue datestart, dateend = groups[0] if (int(datestart) <= intdate) & (int(dateend) >= intdate): kernels.append(ck) nck += 1 """ use the predicted kernels if there are no rec """ if nck == 0: print("Using predicted CK") ckpattern = r"juno_sc_pre_([0-9]{6})_([0-9]{6})\S*" for ck in cks: fname = os.path.basename(ck) groups = re.findall(ckpattern, fname) if len(groups) == 0: continue datestart, dateend = groups[0] if (int(datestart) <= intdate) & (int(dateend) >= intdate): kernels.append(ck) nck += 1 spkpattern = r"spk_rec_([0-9]{6})_([0-9]{6})\S*" nspk = 0 for spk in spks1: fname = os.path.basename(spk) groups = re.findall(spkpattern, fname) if len(groups) == 0: continue datestart, dateend = groups[0] if (int(datestart) <= intdate) & (int(dateend) >= intdate): kernels.append(spk) nspk += 1 """ use the predicted kernels if there are no rec """ if nspk == 0: print("Using predicted SPK") spkpattern = r"spk_pre_([0-9]{6})_([0-9]{6})\S*" for spk in spks1: fname = os.path.basename(spk) groups = re.findall(spkpattern, fname) if len(groups) == 0: continue datestart, dateend = groups[0] if (int(datestart) <= intdate) & (int(dateend) >= intdate): kernels.append(spk) nspk += 1 assert nck * nspk > 0, "Kernels not found for the given date range!" # load the latest updates for these kernels.append(iks[-1]) kernels.append(spks2[-1]) kernels.append(spks3[-1]) kernels.append(spks4[-1]) kernels.append(pcks[-1]) kernels.append(fks[-1]) kernels.append(sclks[-1]) kernels.append(lsks[-1]) kernels.append("spk/juno_rec_orbit.bsp") kernels.append("spk/juno_pred_orbit.bsp") return check_and_download_kernels(kernels, KERNEL_DATAFOLDER)