From f349ddeb1f13ae997a2b13fa95cff68271c7dbca Mon Sep 17 00:00:00 2001
From: Summer Stapleton <sgstapleton@usgs.gov>
Date: Wed, 28 Aug 2019 10:00:53 -0700
Subject: [PATCH] Functioning Kernel Split Notebook (#255)

* Notebook for CK/SPK Kernel Slicing

* Initial spkmerged configuration file output

* Functioning kernel split script
---
 notebooks/KernelSlice.ipynb | 236 ++++++++++++++++++++++++++++++++++++
 1 file changed, 236 insertions(+)
 create mode 100644 notebooks/KernelSlice.ipynb

diff --git a/notebooks/KernelSlice.ipynb b/notebooks/KernelSlice.ipynb
new file mode 100644
index 0000000..ebb8963
--- /dev/null
+++ b/notebooks/KernelSlice.ipynb
@@ -0,0 +1,236 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import spiceypy as spice\n",
+    "import pvl\n",
+    "import os\n",
+    "import re\n",
+    "import subprocess\n",
+    "from ale import util\n",
+    "from itertools import chain\n",
+    "import io\n",
+    "import networkx as nx\n",
+    "\n",
+    "\n",
+    "# These should be provided when running this script. \n",
+    "cube = \"/work/users/sgstapleton/kernel_split/EN1072174528M.cub\"\n",
+    "output_dir = \"/work/users/sgstapleton/kernel_split/\" # Output dir for created kernel files\n",
+    "data_dir = \"/usgs/cpkgs/isis3/data/\" # Dir of where to pull original kernels from\n",
+    "\n",
+    "    \n",
+    "def get_reference_id(bc_filename):\n",
+    "    brief = subprocess.check_output([\"ckbrief\", bc_filename])\n",
+    "    reference = None\n",
+    "\n",
+    "    for line in brief.splitlines():\n",
+    "        line = str(line)\n",
+    "        if('Object:' in line):\n",
+    "            reference = int(line.strip(\"''\").split()[1])\n",
+    "            \n",
+    "    return reference\n",
+    "\n",
+    "\n",
+    "def add_light_time_correction(cube_info, kernels):\n",
+    "    \n",
+    "    furnished_kerns = spice.furnsh(kernels)\n",
+    "    \n",
+    "    image_start_et = spice.scs2e(cube_info['SpacecraftID'], cube_info['SpacecraftClockCount'])\n",
+    "    image_end_et = image_start_et + cube_info['ExposureDuration']\n",
+    "    \n",
+    "    inst_state, inst_lt = spice.spkez(cube_info['SpacecraftID'], (image_start_et + image_end_et)/2, 'J2000', 'LT+S', 0)\n",
+    "    target_state, target_lt = spice.spkez(cube_info['TargetID'], (image_start_et + image_end_et)/2, 'J2000', 'LT+S', 0)\n",
+    "    \n",
+    "    lt_pad = max(abs(inst_lt), abs(target_lt)) + 15\n",
+    "    \n",
+    "    # Eph time\n",
+    "    padded_start_et = image_start_et - lt_pad\n",
+    "    padded_end_et = image_end_et + lt_pad\n",
+    "    \n",
+    "    # Padded times\n",
+    "    padded_start_sclk = spice.sce2s(cube_info['SpacecraftID'], padded_start_et)\n",
+    "    padded_end_sclk = spice.sce2s(cube_info['SpacecraftID'], padded_end_et)\n",
+    "    padded_start_utc = spice.et2utc(padded_start_et, 'c', 3)\n",
+    "    padded_end_utc = spice.et2utc(padded_end_et, 'c', 3)\n",
+    "\n",
+    "    cube_info.update(PaddedStartTimeSCLK = padded_start_sclk)\n",
+    "    cube_info.update(PaddedEndTimeSCLK = padded_end_sclk)\n",
+    "    cube_info.update(PaddedStartTimeUTC = padded_start_utc)\n",
+    "    cube_info.update(PaddedEndTimeUTC = padded_end_utc)\n",
+    "    \n",
+    "\n",
+    "def get_body_ids(spk_file, body_id):\n",
+    "    brief = subprocess.check_output([\"brief\", \"-c {}\".format(spk_file)])\n",
+    "    \n",
+    "    # Convert from bytes\n",
+    "    brief = brief.decode(\"utf-8\")\n",
+    "    brief_io = io.StringIO(brief)\n",
+    "    line = brief_io.readline()\n",
+    "    edge_list = []\n",
+    "        \n",
+    "    while(line):\n",
+    "        \n",
+    "        if(\"w.r.t\" in line):\n",
+    "                bodies_results = re.findall('\\((.*?)\\)', line)\n",
+    "                edge_list.append(bodies_results)\n",
+    "                        \n",
+    "        line = brief_io.readline()\n",
+    "        \n",
+    "    G = nx.DiGraph()\n",
+    "    G.add_edges_from(edge_list)\n",
+    "       \n",
+    "    body_ids = []\n",
+    "    for path in nx.all_simple_paths(G, body_id, '0'):\n",
+    "        body_ids = body_ids + path\n",
+    "        \n",
+    "    body_ids = set(body_ids)\n",
+    "\n",
+    "    return body_ids\n",
+    "\n",
+    "\n",
+    "def output_spkmerge_config(config_file, cube_info, output_dir):\n",
+    "    \n",
+    "    with open(config_file, \"w+\") as config:\n",
+    "        config.write('''LEAPSECONDS_KERNEL     = {}\\n'''.format(cube_info['LeapSecond'][0]))\n",
+    "    \n",
+    "        for kern in cube_info['InstrumentPosition']:\n",
+    "            \n",
+    "            basename = os.path.basename(kern).split('.')[0]\n",
+    "            filename, file_extension = os.path.splitext(kern)\n",
+    "            new_kern = output_dir + basename + \"_merged\" + file_extension\n",
+    "            \n",
+    "            config.write('''      SPK_KERNEL             = {}\\n'''.format(new_kern))\n",
+    "\n",
+    "            body_ids = get_body_ids(kern, str(cube_info['SpacecraftID']))\n",
+    "\n",
+    "            for body in body_ids:\n",
+    "\n",
+    "                if body != '0':\n",
+    "\n",
+    "                    config.write('''         SOURCE_SPK_KERNEL   = {}\\n'''.format(kern))\n",
+    "                    config.write('''            INCLUDE_COMMENTS = no\\n''')\n",
+    "                    config.write('''            BODIES              = {}\\n'''.format(body))\n",
+    "                    config.write('''            BEGIN_TIME          = {}\\n'''.format(cube_info['PaddedStartTimeUTC']))\n",
+    "                    config.write('''            END_TIME            = {}\\n'''.format(cube_info['PaddedEndTimeUTC']))\n",
+    "                    \n",
+    "    config.close()\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# These are the processing steps. This will make use of the cube provided further up to create smaller, \n",
+    "# more manageable kernel files for ale testing purposes. This currently only handles ck and spk files.\n",
+    "\n",
+    "# Get dictionary of kernel lists from cube\n",
+    "cube_info = util.generate_kernels_from_cube(cube, 'dict')\n",
+    "\n",
+    "# Replace path variables with absolute paths for kernels\n",
+    "for kernel_list in cube_info:\n",
+    "    for index, kern in enumerate(cube_info[kernel_list]):\n",
+    "        if kern is not None:\n",
+    "            cube_info[kernel_list][index] = data_dir + kern.strip('$')\n",
+    "            \n",
+    "# Create ordered list of kernels for furnishing\n",
+    "kernels = [kernel for kernel in chain.from_iterable(cube_info.values()) if isinstance(kernel, str)]\n",
+    "                \n",
+    "# Loads cube as pvl to extract rest of data\n",
+    "cube_pvl = pvl.load(cube)\n",
+    "               \n",
+    "# Save other necesary info in cube_info dict\n",
+    "cube_info.update(SpacecraftClockCount = cube_pvl['IsisCube']['Instrument']['SpacecraftClockCount'])\n",
+    "cube_info.update(ExposureDuration = cube_pvl['IsisCube']['Instrument']['ExposureDuration'].value * 0.001)\n",
+    "cube_info.update(TargetID = spice.bods2c(cube_pvl['IsisCube']['Instrument']['TargetName']))\n",
+    "cube_info.update(SpacecraftID = spice.bods2c(cube_pvl['IsisCube']['Instrument']['SpacecraftName']))\n",
+    "\n",
+    "# Add lighttime-corrected SCLK values to cube_info\n",
+    "add_light_time_correction(cube_info, kernels)\n",
+    "\n",
+    "# For each binary ck kernel specified in cube, run the ckslicer, comment and to-transfer commands\n",
+    "for ck in cube_info['InstrumentPointing']:\n",
+    "    if ck.endswith('.bc'):\n",
+    "        \n",
+    "        # Get reference id associated with ck\n",
+    "        reference_id = get_reference_id(ck)\n",
+    "        \n",
+    "        ck_filename = os.path.basename(ck).split('.')[0]\n",
+    "        ck_path, ck_file_extension = os.path.splitext(ck)\n",
+    "        output_kern = output_dir + ck_filename + '_sliced' + ck_file_extension\n",
+    "        \n",
+    "        # Create new sliced ck kernel\n",
+    "        ckslicer_command = [\"./ckslicer\", \n",
+    "                                '-LSK {}'.format(cube_info['LeapSecond'][0]), \n",
+    "                                '-SCLK {}'.format(cube_info['SpacecraftClock'][0]), \n",
+    "                                '-INPUTCK {}'.format(ck), \n",
+    "                                '-OUTPUTCK {}'.format(output_kern),\n",
+    "                                '-ID {}'.format(reference_id),\n",
+    "                                '-TIMETYPE {}'.format('SCLK'),\n",
+    "                                '-START {}'.format(cube_info['PaddedStartTimeSCLK']),\n",
+    "                                '-STOP {}'.format(cube_info['PaddedEndTimeSCLK'])]\n",
+    "        subprocess.call(ckslicer_command)\n",
+    "        \n",
+    "        # Remove old comments from new ck kernel\n",
+    "        commnt_command = ['commnt', '-d {}'.format(output_kern)]\n",
+    "        subprocess.call(commnt_command)\n",
+    "        \n",
+    "        # Makes a new txt file for the only comments that should be stored in the new ck file\n",
+    "        with open(\"temp_commnts.txt\",\"w+\") as f:\n",
+    "            f.write(\"This CK is for testing with the image: {}\\n\".format(cube))\n",
+    "            f.write(\"\\nThis CK was generated using the following command: {}\\n\".format(\" \".join(ckslicer_command)))\n",
+    "        \n",
+    "        # Add new comments to new ck kernel\n",
+    "        new_commnts_command = [\"commnt\", \"-a {}\".format(output_kern), \"temp_commnts.txt\"]\n",
+    "        subprocess.call(new_commnts_command)\n",
+    "        \n",
+    "        # Create the transfer file of the new ck kernel\n",
+    "        subprocess.call([\"toxfr\", output_kern])\n",
+    "\n",
+    "# Create the config file for the spkmerge command\n",
+    "output_spkmerge_config(output_dir + \"spk.config\", cube_info, output_dir)\n",
+    "\n",
+    "# Run the spkmerge command\n",
+    "spkmerge_command = [\"spkmerge\", output_dir + \"spk.config\"]\n",
+    "subprocess.call(spkmerge_command)\n",
+    "\n",
+    "# Clean up temp config file\n",
+    "os.remove(output_dir + \"spk.config\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.7.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
-- 
GitLab