diff --git a/docs/getting-started/csm-stack/csm-sandbox.ipynb b/docs/getting-started/csm-stack/csm-sandbox.ipynb new file mode 100644 index 0000000..bff7cf5 --- /dev/null +++ b/docs/getting-started/csm-stack/csm-sandbox.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CSM Sandbox\n", + "\n", + "[Download This Notebook :octicons-file-code-16:](https://raw.githubusercontent.com/DOI-USGS/asc-public-docs/refs/heads/main/docs/getting-started/csm-stack/csm-sandbox.ipynb){ .md-button .md-button--primary } \n", + "[Download Example Data :material-folder-arrow-down:](https://raw.githubusercontent.com/DOI-USGS/asc-public-docs/refs/heads/main/docs/getting-started/csm-stack/image-to-ground/image-to-ground.zip){ .md-button .md-button--primary }\n", + "\n", + "### Install Knoten & Prerequisites\n", + "```sh\n", + "mamba install -c conda-forge knoten=0.4 conda-forge matplotlib ipywidgets ipympl>=0.9.6\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget\n", + "import os # File Path Joining\n", + "import json # Read ISD as python dictionary\n", + "import copy # Important to be able to modify the ISD\n", + "\n", + "from knoten import csm # Knoten CSM\n", + "\n", + "import matplotlib.pyplot as plt # Math and Plotting Tools\n", + "import ipywidgets as widgets\n", + "from ipywidgets import Layout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Methods for reading/printing stats" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def print_stats(dict, search_keys):\n", + " for search_key in search_keys:\n", + " print(f\"{search_key+\": \":<25}\" + str(dict[search_key]))\n", + "\n", + "def plot_footprint(lons, lats, aspect):\n", + " plt.close()\n", + " plt.rcParams[\"figure.figsize\"] = aspect\n", + " plt.axes().set_aspect('equal','datalim')\n", + " plt.plot(lons, lats)\n", + " plt.xlabel(\"Longitude (deg)\")\n", + " plt.ylabel(\"Latitude (deg)\")\n", + " plt.title(\"CSM footprint\")\n", + " plt.show()\n", + "\n", + "def plot_footprint_comparison(fp1, fp2, aspect):\n", + " plt.clf() # clear previous figure\n", + " plt.rcParams[\"figure.figsize\"] = aspect # set aspect ratio of plot\n", + " plt.axes().set_aspect('equal','datalim') \n", + " fp1_plot, = plt.plot(fp1[0], fp1[1], 'b') # Plot footprint 1 in blue\n", + "\n", + " margin = 0.001 # boundaries centered on footprint 1\n", + " fp1_lim_x = plt.xlim()\n", + " fp1_lim_y = plt.ylim()\n", + " fp1_lim_x = (fp1_lim_x[0] - margin, fp1_lim_x[1] + margin)\n", + " fp1_lim_y = (fp1_lim_y[0] - margin, fp1_lim_y[1] + margin)\n", + "\n", + " fp2_plot, = plt.plot(fp2[0], fp2[1], 'r') # Plot footprint 2 in red\n", + " plt.title(\"Original vs. Modified Footprint\") # Title and axis labels\n", + " plt.xlabel(\"Longitude (deg)\")\n", + " plt.ylabel(\"Latitude (deg)\")\n", + " fp1_plot.set_label(fp1[2]) # Labels/Legend\n", + " fp2_plot.set_label(fp2[2])\n", + " plt.legend()\n", + " plt.xlim(fp1_lim_x) # Set Size\n", + " plt.ylim(fp1_lim_y)\n", + " plt.show() # Show plot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Stats/Footprint of original ISD" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "focal_length_model: {'focal_length': 352.9271664}\n", + "detector_center: {'line': 0.430442527, 'sample': 2542.96099}\n", + "optical_distortion: {'radial': {'coefficients': [-0.0073433925920054505, 2.8375878636241697e-05, 1.2841989124027099e-08]}}\n", + "center_ephemeris_time: 297088762.2425226\n" + ] + } + ], + "source": [ + "# Load Dict from JSON-style ISD File\n", + "data_dir = 'image-to-ground'\n", + "isd_file = os.path.join(data_dir, 'isd_file.json')\n", + "\n", + "with open(isd_file) as json_file:\n", + " isd_dict = json.load(json_file)\n", + "\n", + "# Print selected values from ISD\n", + "print_stats(isd_dict, ('focal_length_model', 'detector_center', 'optical_distortion', 'center_ephemeris_time'))\n", + "\n", + "# Create Camera Model\n", + "camera = csm.create_csm(isd_file)\n", + "\n", + "# Get the footprint using the model\n", + "boundary = csm.generate_boundary((isd_dict[\"image_lines\"], isd_dict[\"image_samples\"]))\n", + "lons, lats, alts = csm.generate_latlon_boundary(camera, boundary)\n", + "\n", + "# # This line can plot the footprint of the original ISD\n", + "# plot_footprint(lons, lats, [5,1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Modify ISD/write to file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adjust Sliders to add or subtract from the values at the following ISD Keys:\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "99f757a292504ab19d2b8db31cbd9cd3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(FloatSlider(value=0.0, description='Focal Length', layout=Layout(width='600px'), max=0.2…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# clear the plot from any previous footprints/plots\n", + "plt.close()\n", + "\n", + "# Copy the ISD Dictionary, we will modify it and compare to the original.\n", + "isd_dict_mod = copy.deepcopy(isd_dict)\n", + "\n", + "print('Adjust Sliders to add or subtract from the values at the following ISD Keys:')\n", + "\n", + "# Slider Widgets\n", + "wide_lay = Layout(width='600px')\n", + "wide_desc = {'description_width': '150px'}\n", + "@widgets.interact(\n", + " fl_add=widgets.FloatSlider(min=-0.25, max=.25, step=0.001, description='Focal Length', layout=wide_lay, style=wide_desc), \n", + " dcl_add=widgets.FloatSlider(min=-4, max=4, step=0.05, description='Detector Center Line', layout=wide_lay, style=wide_desc),\n", + " dcs_add=widgets.FloatSlider(min=-2.5, max=2.5, step=0.02, description='Detector Center Sample', layout=wide_lay, style=wide_desc),\n", + " opt_x=widgets.FloatSlider(min=-0.001, max=0.001, step=0.00001, description='Optical Distortion X', layout=wide_lay, style=wide_desc, readout_format='.5f'),\n", + " opt_y=widgets.FloatSlider(min=-2e-6, max=2e-6, step=2e-8, description='Optical Distortion Y', layout=wide_lay, style=wide_desc, readout_format='.1e'),\n", + " opt_z=widgets.FloatSlider(min=-1e-8, max=1e-8, step=1e-10, description='Optical Distortion Z', layout=wide_lay, style=wide_desc, readout_format='.1e'),\n", + " ect_add=widgets.FloatSlider(min=-1e-2, max=1e-2, step=1e-4, description='Exposure (Center) Time', layout=wide_lay, style=wide_desc, readout_format='.4f')\n", + " )\n", + "# This function executed whenever one of the slider widgets is adjusted\n", + "def exec_widget_function(fl_add, dcl_add, dcs_add, opt_x, opt_y, opt_z, ect_add):\n", + "\n", + " # If you're curious where the ISD values came from, \n", + " # Detector Center was from NAIF Boresight Line/Sample\n", + " # Optical Distortion was from NAIF OD_K\n", + " # ISIS uses the NAIF Keywords, but Knoten CSM uses other derived ISD values.\n", + "\n", + " new_values = {\n", + " 'focal_length_model': {'focal_length': 352.9271664 + fl_add},\n", + " 'detector_center': {'line': 0.430442527 + dcl_add, 'sample': 2542.96099 + dcs_add},\n", + " 'optical_distortion': {'radial': {'coefficients': [-0.007343 + opt_x, 2.838e-05 + opt_y, 1.284e-08 + opt_z]}},\n", + " 'center_ephemeris_time': 297088762.2425226 + ect_add\n", + " }\n", + "\n", + " # Modify Values in Dictionary\n", + " for key,value in new_values.items(): \n", + " isd_dict_mod[key] = new_values[key]\n", + "\n", + " # Write ISD to file\n", + " isd_file_mod = os.path.join(data_dir, 'isd_file_mod.json')\n", + " with open(isd_file_mod, 'w') as json_file:\n", + " json.dump(isd_dict_mod, json_file, indent=4)\n", + "\n", + " print_stats(isd_dict_mod, ('focal_length_model', 'detector_center', 'optical_distortion', 'center_ephemeris_time'))\n", + "\n", + " # Create Camera Model\n", + " camera = csm.create_csm(isd_file_mod)\n", + "\n", + " # Get the footprint using the model\n", + " boundary_mod = csm.generate_boundary((isd_dict_mod[\"image_lines\"], isd_dict_mod[\"image_samples\"]))\n", + " lons_mod, lats_mod, alts_mod = csm.generate_latlon_boundary(camera, boundary_mod)\n", + "\n", + " # Plot it\n", + " plot_footprint_comparison((lons, lats, \"Original\"),(lons_mod, lats_mod, \"Modified\"), [7,3])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "knoten", + "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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/getting-started/csm-stack/image-to-ground-tutorial.ipynb b/docs/getting-started/csm-stack/image-to-ground-tutorial.ipynb index 901a750..ac5dd4b 100644 --- a/docs/getting-started/csm-stack/image-to-ground-tutorial.ipynb +++ b/docs/getting-started/csm-stack/image-to-ground-tutorial.ipynb @@ -51,7 +51,7 @@ "metadata": {}, "source": [ "### 2. Generate an ISD from a Cube\n", - "We will use MRO data located in the `data/image_to_ground` folder containing a cube and necessary kernels for ISD (Image Support Data) generation. \n", + "We will use MRO data located in the `image-to-ground` folder containing a cube and necessary kernels for ISD (Image Support Data) generation. \n", "*Note*: If your cube already has attached spice data, do you not have to specify kernels in the `props` param and can pass in an empty dict `{}` instead." ] }, @@ -68,7 +68,7 @@ "import os\n", "\n", "# Set local data directory and paths\n", - "data_dir = '../data/image_to_ground'\n", + "data_dir = 'image-to-ground'\n", "cube_file = os.path.join(data_dir, 'B10_013341_1010_XN_79S172W.cub')\n", "isd_file = os.path.join(data_dir, 'isd_file.json')\n", "\n", @@ -194,7 +194,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "knoten", "language": "python", "name": "python3" }, @@ -208,7 +208,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.0" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub b/docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub similarity index 100% rename from docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub rename to docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub diff --git a/docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W_0.bsp b/docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W_0.bsp similarity index 100% rename from docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W_0.bsp rename to docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W_0.bsp diff --git a/docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W_1.bsp b/docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W_1.bsp similarity index 100% rename from docs/getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W_1.bsp rename to docs/getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W_1.bsp diff --git a/docs/getting-started/data/image_to_ground/image-to-ground.zip b/docs/getting-started/csm-stack/image-to-ground/image-to-ground.zip similarity index 100% rename from docs/getting-started/data/image_to_ground/image-to-ground.zip rename to docs/getting-started/csm-stack/image-to-ground/image-to-ground.zip diff --git a/docs/getting-started/data/image_to_ground/isd_file.json b/docs/getting-started/csm-stack/image-to-ground/isd_file.json similarity index 100% rename from docs/getting-started/data/image_to_ground/isd_file.json rename to docs/getting-started/csm-stack/image-to-ground/isd_file.json diff --git a/docs/getting-started/data/image_to_ground/mro_B10_72W.tm b/docs/getting-started/csm-stack/image-to-ground/mro_B10_72W.tm similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_B10_72W.tm rename to docs/getting-started/csm-stack/image-to-ground/mro_B10_72W.tm diff --git a/docs/getting-started/data/image_to_ground/mro_ctx_v11.ti b/docs/getting-started/csm-stack/image-to-ground/mro_ctx_v11.ti similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_ctx_v11.ti rename to docs/getting-started/csm-stack/image-to-ground/mro_ctx_v11.ti diff --git a/docs/getting-started/data/image_to_ground/mro_sc_psp_090526_090601_0_sliced_-74000.bc b/docs/getting-started/csm-stack/image-to-ground/mro_sc_psp_090526_090601_0_sliced_-74000.bc similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_sc_psp_090526_090601_0_sliced_-74000.bc rename to docs/getting-started/csm-stack/image-to-ground/mro_sc_psp_090526_090601_0_sliced_-74000.bc diff --git a/docs/getting-started/data/image_to_ground/mro_sc_psp_090526_090601_1_sliced_-74000.bc b/docs/getting-started/csm-stack/image-to-ground/mro_sc_psp_090526_090601_1_sliced_-74000.bc similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_sc_psp_090526_090601_1_sliced_-74000.bc rename to docs/getting-started/csm-stack/image-to-ground/mro_sc_psp_090526_090601_1_sliced_-74000.bc diff --git a/docs/getting-started/data/image_to_ground/mro_sclkscet_00082_65536.tsc b/docs/getting-started/csm-stack/image-to-ground/mro_sclkscet_00082_65536.tsc similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_sclkscet_00082_65536.tsc rename to docs/getting-started/csm-stack/image-to-ground/mro_sclkscet_00082_65536.tsc diff --git a/docs/getting-started/data/image_to_ground/mro_v16.tf b/docs/getting-started/csm-stack/image-to-ground/mro_v16.tf similarity index 100% rename from docs/getting-started/data/image_to_ground/mro_v16.tf rename to docs/getting-started/csm-stack/image-to-ground/mro_v16.tf diff --git a/docs/getting-started/data/image_to_ground/naif0012.tls b/docs/getting-started/csm-stack/image-to-ground/naif0012.tls similarity index 100% rename from docs/getting-started/data/image_to_ground/naif0012.tls rename to docs/getting-started/csm-stack/image-to-ground/naif0012.tls diff --git a/docs/getting-started/data/image_to_ground/pck00008.tpc b/docs/getting-started/csm-stack/image-to-ground/pck00008.tpc similarity index 100% rename from docs/getting-started/data/image_to_ground/pck00008.tpc rename to docs/getting-started/csm-stack/image-to-ground/pck00008.tpc diff --git a/docs/getting-started/csm-stack/knoten-camera-tutorial.ipynb b/docs/getting-started/csm-stack/knoten-camera-tutorial.ipynb index 9f43384..e963b35 100644 --- a/docs/getting-started/csm-stack/knoten-camera-tutorial.ipynb +++ b/docs/getting-started/csm-stack/knoten-camera-tutorial.ipynb @@ -60,7 +60,7 @@ "metadata": {}, "outputs": [], "source": [ - "data_dir = '../data/image_to_ground'\n", + "data_dir = 'image-to-ground'\n", "filename = os.path.join(data_dir, \"B10_013341_1010_XN_79S172W.IMG\")\n", "\n", "downloader = urllib.request.URLopener()\n", @@ -315,7 +315,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "knoten", "language": "python", "name": "python3" }, @@ -329,7 +329,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.12.7" } }, "nbformat": 4, diff --git a/docs/getting-started/using-ale/isd-generate.md b/docs/getting-started/using-ale/isd-generate.md index deb812a..8552ca6 100644 --- a/docs/getting-started/using-ale/isd-generate.md +++ b/docs/getting-started/using-ale/isd-generate.md @@ -70,7 +70,7 @@ isd_generate [--arguments] [your-image-name] !!! example "isd_generate default run, no arguments" - To run isd_generate with no arguments on a .cub named [B10_013341_1010_XN_79S172W.cub](../../getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub): + To run isd_generate with no arguments on a .cub named [B10_013341_1010_XN_79S172W.cub](../../getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub): ```sh isd_generate B10_013341_1010_XN_79S172W.cub @@ -85,7 +85,7 @@ By default, this is your image's name, with a .json file extension (i.e. `B10_01 !!! example "Specifying Output" - [Example .cub](../../getting-started/data/image_to_ground/B10_013341_1010_XN_79S172W.cub) + [Example .cub](../../getting-started/csm-stack/image-to-ground/B10_013341_1010_XN_79S172W.cub) To output to a specified filename, use `--out` or `-o`. This example outputs a 'MyIsd.json' file: @@ -121,8 +121,8 @@ When using an NAIF SPICE Data, you can specify a metakernel using the `--kernel` !!! example "Using a NaifSpice Driver with a metakernel" Folder with example NAIF Data: - [[Download as .zip](../../getting-started/data/image_to_ground/image-to-ground.zip)] - [[View in GitHub](https://github.com/DOI-USGS/asc-public-docs/tree/main/docs/getting-started/data/image_to_ground)] + [[Download as .zip](../../getting-started/csm-stack/image-to-ground/image-to-ground.zip)] + [[View in GitHub](https://github.com/DOI-USGS/asc-public-docs/tree/main/docs/getting-started/csm-stack/image-to-ground)] This folder contains NAIF Data consisting of the various kernels necessary to generate an ISD for the `B10_013341_1010_XN_79S172W` image. diff --git a/mkdocs.yml b/mkdocs.yml index e74b4e8..b832997 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,7 +41,8 @@ nav: - Home: getting-started/index.md - CSM Stack: - Generating an ISD, creating a CSM model, and converting coordinates: getting-started/csm-stack/image-to-ground-tutorial.ipynb - - Knoten - Basic Camera Operations: getting-started/csm-stack/knoten-camera-tutorial.ipynb + - Knoten - Basic Camera Operations: getting-started/csm-stack/knoten-camera-tutorial.ipynb + - CSM Sandbox: getting-started/csm-stack/csm-sandbox.ipynb - "Using ISIS: First Steps": - Introduction to ISIS: getting-started/using-isis-first-steps/introduction-to-isis.md - Locating and Ingesting Image Data: getting-started/using-isis-first-steps/locating-and-ingesting-image-data.md