From 290487caa67a63dbc822c285124ae50fa21de2ac Mon Sep 17 00:00:00 2001 From: Hatice Karatay <66814693+haticekaratay@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:13:27 -0500 Subject: [PATCH] Add acs_epsf_notebook (#194) * added acs_focus_diverse_epsfs for review acstools 3.7.0 is now available, so the notebooks is ready for review * Add files via upload * Add files via upload * Add files via upload * updated acs_focus_diverse_epsfs.ipynb updated to hopefully fix CI issues * Update notebooks/ACS/acs_focus_diverse_epsfs/requirements.txt Co-authored-by: Hatice Karatay <66814693+haticekaratay@users.noreply.github.com> * clearing cell output --------- Co-authored-by: Gagandeep Anand <30330521+gsanand@users.noreply.github.com> --- .../acs_focus_diverse_epsfs.ipynb | 429 ++++++++++++++++++ .../acs_focus_diverse_epsfs/input_ipsoots.txt | 10 + .../acs_focus_diverse_epsfs/requirements.txt | 8 + 3 files changed, 447 insertions(+) create mode 100644 notebooks/ACS/acs_focus_diverse_epsfs/acs_focus_diverse_epsfs.ipynb create mode 100644 notebooks/ACS/acs_focus_diverse_epsfs/input_ipsoots.txt create mode 100644 notebooks/ACS/acs_focus_diverse_epsfs/requirements.txt diff --git a/notebooks/ACS/acs_focus_diverse_epsfs/acs_focus_diverse_epsfs.ipynb b/notebooks/ACS/acs_focus_diverse_epsfs/acs_focus_diverse_epsfs.ipynb new file mode 100644 index 000000000..919b987b6 --- /dev/null +++ b/notebooks/ACS/acs_focus_diverse_epsfs/acs_focus_diverse_epsfs.ipynb @@ -0,0 +1,429 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a9d01468", + "metadata": {}, + "source": [ + "This notebook highlights how to use the focus_diverse_psfs module within acstools to retrieve empirical, focus-diverse ePSFs for ACS/WFC data. Please see the [webtool](https:https://acspsf.stsci.edu/), [ACS ISR 2018-08](https://ui.adsabs.harvard.edu/abs/2018acs..rept....8B/abstract), and [ACS ISR 2023-06](https://ui.adsabs.harvard.edu/abs/2023acs..rept....6A/abstract) for more details." + ] + }, + { + "cell_type": "markdown", + "id": "133fe01a", + "metadata": {}, + "source": [ + "## Imports" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a81500b6", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from astropy.io import fits\n", + "from astroquery.mast import Observations\n", + "\n", + "import ipywidgets as widgets\n", + "import matplotlib.colors as colors\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# import the focus_diverse_psfs functions from acstools \n", + "from acstools.focus_diverse_epsfs import psf_retriever, multi_psf_retriever, interp_epsf" + ] + }, + { + "cell_type": "markdown", + "id": "a319cda8", + "metadata": {}, + "source": [ + "## Downloading and Examining a Single Focus-Diverse ePSF file" + ] + }, + { + "cell_type": "markdown", + "id": "c5ce3a38", + "metadata": {}, + "source": [ + "Let's begin with downloading the focus-diverse ePSF FITS file that matches a single observation of our choosing. For this example, we will aim to retrieve the ePSF file for the observation rootname \"jds408jsq\", from GO-15445 (PI W. Keel). \n", + "\n", + "Please note that only IPPPSSOOT formats will work (e.g. jds408jsq), and the tool does not support inputs in the form of association IDs or product names (e.g. jds408010 or jds408011).\n", + "\n", + "\n", + "Make sure to change the variable \"download_location\" to an existing folder on your local machine." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2529639", + "metadata": {}, + "outputs": [], + "source": [ + "%%time \n", + "\n", + "# example of a single retrieval\n", + "\n", + "\n", + "# Set the download location to the current working directory\n", + "download_location = os.path.join(os.getcwd(), 'downloads')\n", + "os.makedirs(download_location, exist_ok=True)\n", + "\n", + "# call the psf_retriever function with observation rootname\n", + "retrieved_download = psf_retriever('jds408jsq', download_location) " + ] + }, + { + "cell_type": "markdown", + "id": "bdd9632d", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "6791eb95", + "metadata": {}, + "source": [ + "The direct return of the psf_retriever function is the retrieved file name. The name has the format %ROOTNAME-STDPBF_ACSWFC_%FILTER_%SM_%F.fits, where the variables are:\n", + "\n", + "%ROOTNAME- this is the image rootname that you passed to psf_retriever, which is appended to allow for easier bookkeeping of retrieved files\n", + "\n", + "%FILTER- this is the ACS/WFC filter that was used in the observation\n", + "\n", + "%SM- Short for \"Servicing Mission\", SM3 or SM4, depending on when the observation was taken.\n", + "\n", + "%F- Best fit focus group that the individual exposures lies within." + ] + }, + { + "cell_type": "markdown", + "id": "cb0ea63d", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "e8e695f8", + "metadata": {}, + "source": [ + "We can now examine the retrieved FITS file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bddab16", + "metadata": {}, + "outputs": [], + "source": [ + "# give path to downloaded file\n", + "retrieved_filepath = os.path.abspath(retrieved_download)\n", + "\n", + "if not os.path.isfile(retrieved_filepath):\n", + " raise FileNotFoundError(f\"Expected file not found at {retrieved_filepath}\")\n", + "\n", + "# open the file with astropy.io\n", + "with fits.open(retrieved_filepath) as hdu:\n", + " hdu.info() # Display basic information about the file" + ] + }, + { + "cell_type": "markdown", + "id": "edcf4f10", + "metadata": {}, + "source": [ + "With the output above, we can see that the dimensions of the file are 101 x 101 x 90. This corresponds to a total of 90 ePSFs, each one with x,y dimensions of 101 x 101. The 90 ePSFs span the range of the two WFC chips and correspond to a 9 x 10 spatial grid (see Figure 1 in [ACS ISR 2018-08](https://ui.adsabs.harvard.edu/abs/2018acs..rept....8B/abstract)). \n", + "\n", + "We show these ePSFs below in a widget which allows you to quickly scroll through and get a sense of the spatial differences. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a434e3c", + "metadata": {}, + "outputs": [], + "source": [ + "# # First, lets grab the image data from the retrieved FITS file\n", + "ePSFs = fits.getdata(retrieved_filepath, ext=0)\n", + "\n", + "\n", + "def show_ePSF(grid_index):\n", + " plt.imshow(ePSFs[grid_index], cmap='viridis', norm=colors.LogNorm(vmin=1e-4), origin='lower')\n", + " cbar = plt.colorbar()\n", + " cbar.set_label('Fractional Energy')\n", + " \n", + " \n", + "widgets.interact(show_ePSF, grid_index=(0, 89, 1))" + ] + }, + { + "cell_type": "markdown", + "id": "c4038320", + "metadata": {}, + "source": [ + "## Batch Downloads" + ] + }, + { + "cell_type": "markdown", + "id": "fe76b86a", + "metadata": {}, + "source": [ + "Here we show how to perform batch downloads for a large set of input rootnames, via two separate methods." + ] + }, + { + "cell_type": "markdown", + "id": "782eba8b", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "3c205482", + "metadata": {}, + "source": [ + "### via an Input Text File" + ] + }, + { + "cell_type": "markdown", + "id": "b063b257", + "metadata": {}, + "source": [ + "With an input text file of one rootname per line, we can use the multi_psf_retriever function with the \"fromTextFile\" parameter set to True to batch download the desired focus-diverse ePSFs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f05f8ff", + "metadata": {}, + "outputs": [], + "source": [ + "# specify the name of the input text file (with one rootname per line),\n", + "# as well as the desired download location for our focus-diverse ePSFs\n", + "\n", + "input_list = 'input_ipsoots.txt'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d0a5472", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "%%time \n", + "\n", + "# use the multi_psf_retriever function to retrieve our ePSFs\n", + "retrieved_downloads = multi_psf_retriever(input_list, download_location)\n", + "\n", + "print('# of matching files: ', len(retrieved_downloads))" + ] + }, + { + "cell_type": "markdown", + "id": "1bb2de4e", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "78c17035", + "metadata": {}, + "source": [ + "### via *astroquery*" + ] + }, + { + "cell_type": "markdown", + "id": "713cd3ef", + "metadata": {}, + "source": [ + "Alternatively, we can use *astroquery* to simply grab the rootnames for all ACS/WFC images within a given HST proposal and retrieve the corresponding focus-diverse ePSFs. \n", + "\n", + "Here we provide an example of using astroquery and the multi_psf_retriever function to grab all matching focus-diverse ePSFs for observations of the Leo P galaxy from GO-13376 (PI K. McQuinn)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68519edf", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# # use astroquery to grab ACS/WFC observations from GO-13376 (PI K. McQuinn)\n", + "obsTable = Observations.query_criteria(obs_collection='HST', proposal_id=\"13376\", \n", + " instrument_name=\"ACS/WFC\", provenance_name=\"CALACS\")\n", + "\n", + "# retrieve the data products for the above observations\n", + "dataProducts = Observations.get_product_list(obsTable)\n", + "\n", + "# filter the data products for just the FLC files from HST, and not the Hubble Advanced Products (HAP) project\n", + "dataProducts = dataProducts[(dataProducts['productSubGroupDescription'] == 'FLC') &\n", + " (dataProducts['type'] == 'S')]\n", + "\n", + "# create a list of corresponding rootnames\n", + "obs_rootnames = list(dataProducts['obs_id'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00e3296a", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "%%time\n", + "\n", + "# use the multi_psf_retriever function to retrieve our ePSFs \n", + "retrieved_downloads = multi_psf_retriever(obs_rootnames, download_location)\n", + "\n", + "print('# of matching files: ', len(retrieved_downloads))" + ] + }, + { + "cell_type": "markdown", + "id": "91ab33c5", + "metadata": {}, + "source": [ + "# Further Spatial Interpolations" + ] + }, + { + "cell_type": "markdown", + "id": "9c6a35bc", + "metadata": {}, + "source": [ + "---" + ] + }, + { + "cell_type": "markdown", + "id": "7bf751ae", + "metadata": {}, + "source": [ + "Users may be interested in further interpolating the provided ePSF array to any arbitrary (x,y) coordinate. The function interp_epsf() allows us to retrieve this (using bi-linear interpolation)." + ] + }, + { + "cell_type": "markdown", + "id": "ea152867", + "metadata": {}, + "source": [ + "For example, we can retrieve the ePSF loaded from its FITS file above and interpolate to x,y = (2000,2000) on WFC1, which is near the middle of the detector along the x-axis, and near the top of the WFC1 chip (and the detector overall). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6fbeebf6", + "metadata": {}, + "outputs": [], + "source": [ + "x = 2000\n", + "y = 2000\n", + "chip = \"WFC1\"\n", + "\n", + "# get interpolated ePSF in supersampled space\n", + "P = interp_epsf(ePSFs, x, y, chip)\n", + "plt.imshow(P, cmap='viridis', norm=colors.LogNorm(vmin=1e-4), origin='lower')\n", + "plt.title('jds408jsq at x,y = (2000,2000) on WFC1')\n", + "plt.colorbar()" + ] + }, + { + "cell_type": "markdown", + "id": "f821d862", + "metadata": {}, + "source": [ + "By default, the ePSFs come with 4x supersampling. We can output them in detector space by setting the \"pixel_space\" = True." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "590fb332", + "metadata": {}, + "outputs": [], + "source": [ + "# get interpolated ePSF in detector space\n", + "P = interp_epsf(ePSFs, x, y, chip,\n", + " pixel_space=True)\n", + "plt.imshow(P, cmap='viridis', norm=colors.LogNorm(vmin=1e-4), origin='lower')\n", + "plt.title('(2000,2000) on WFC1 (Detector Space)')\n", + "plt.colorbar()" + ] + }, + { + "cell_type": "markdown", + "id": "d6460c6d", + "metadata": {}, + "source": [ + "Lastly, we can shift the ePSF to any sub-pixel phase by specifying the individual x and y subpixel offsets. The code uses bi-cubic interpolation to perform these sub-pixel phase shifts. \n", + "\n", + "Note that pixel_space must be set to True to use these subpixel offsets. Also note that the code only supports this bi-cubic interpolation to the second decimal place (e.g. subpixel_x = 0.77 and subpixel_y = 0.33)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f74f8caa", + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "# # get interpolated ePSF in detector space with specified sub-pixel shifts\n", + "P = interp_epsf(ePSFs, x, y, chip,\n", + " pixel_space=True, \n", + " subpixel_x=0.77, subpixel_y=0.33)\n", + "\n", + "plt.imshow(P, cmap='viridis', norm=colors.LogNorm(vmin=1e-4), origin='lower')\n", + "plt.title('(2000.77,2000.33) on WFC1 (Detector Space)')\n", + "plt.colorbar()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/ACS/acs_focus_diverse_epsfs/input_ipsoots.txt b/notebooks/ACS/acs_focus_diverse_epsfs/input_ipsoots.txt new file mode 100644 index 000000000..73192ba61 --- /dev/null +++ b/notebooks/ACS/acs_focus_diverse_epsfs/input_ipsoots.txt @@ -0,0 +1,10 @@ +j6d508ojq +j6d508olq +j6d508orq +j6d508otq +j6d508paq +j6d508pcq +j6d509yrq +j6d509ysq +j6d509yuq +j6d509ywq \ No newline at end of file diff --git a/notebooks/ACS/acs_focus_diverse_epsfs/requirements.txt b/notebooks/ACS/acs_focus_diverse_epsfs/requirements.txt new file mode 100644 index 000000000..8e37965bd --- /dev/null +++ b/notebooks/ACS/acs_focus_diverse_epsfs/requirements.txt @@ -0,0 +1,8 @@ +acstools==3.7.0 +astropy==5.1.1 +astroquery==0.4.6 +dask==2022.11.1 +ipywidgets==8.0.2 +matplotlib==3.6.2 +numpy==1.23.4 +scipy==1.11.4 \ No newline at end of file