{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculating WFC3 zeropoints with STSynphot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This notebook shows how to calculate photometric zeropoints using the python package `stsynphot` for any WFC3 detector, filter, date, or aperture. This is especially useful for calculating Vegamag zeropoints which require an input spectrum. The notebook is also useful for computing time-dependent WFC3/UVIS zeropoints for any observation date, as the values listed in WFC3 ISR 2021-04 are defined for the reference epoch. As of mid-2021, the WFC3/IR zeropoints are not time-dependent). \n", "\n", "To install stsynphot, activate your conda environment in a bash shell and enter the command `pip install stsynphot`. More documentation on stsynphot is available [here](https://stsynphot.readthedocs.io/en/latest/index.html). Using stsynphot requires downloading the throughput curves for the HST instruments and optical path. One method of doing this is shown below. More information can be found [here](https://www.stsci.edu/hst/instrumentation/reference-data-for-calibration-and-tools/synphot-throughput-tables)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### TOC:\n", "\n", "* [Downloading throughput tables and defining variables](#envvar)\n", "* [Setting up the 'obsmode' string](#inps)\n", "* [Basic usage for a single 'obsmode'](#usage)\n", "* [Computing zeropoints and other photometric properties](#zps)\n", "* [Iterating over multiple 'obsmodes'](#iterate)\n", "* [Creating and plotting 'total system throughput' tables](#curves)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. Downloading throughput tables and defining variables \n", "This section obtains the WFC3 throughput component tables for use with synphot" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "\n", "#cmd_input = 'curl -O ftp://archive.stsci.edu/pub/hst/pysynphot/synphot1.tar.gz'\n", "#os.system(cmd_input)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once the files are downloaded, unpack the files and set the environment variable `PYSYN_CDBS` to the path of the unpacked files." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# os.environ['PYSYN_CDBS'] = '/YOUR/PATH/HERE/'\n", "os.environ['PYSYN_CDBS'] = '/grp/hst/cdbs/' # for STScI staff" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import stsynphot as stsyn\n", "\n", "from astropy.table import Table\n", "from astropy.time import Time\n", "from synphot import Observation\n", "\n", "#Rather than downloading the entire calspec database (synphot6.tar.gz), \n", "#we can point directly to the latest Vega spectrum which is required for computing VEGAMAG\n", "\n", "vega_url = 'https://ssb.stsci.edu/trds/calspec/alpha_lyr_stis_010.fits'\n", "stsyn.Vega = stsyn.spectrum.SourceSpectrum.from_file(vega_url)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Setting up the 'obsmode' string" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Parameters to set in the `obsmode` string include: 1.) detector, 2.) filter, 3.) observation date (UVIS only), and 4.) aperture size (in arcsec). \n", "\n", "Note that a 6.0\" aperture is considered to be 'infinite', thus containing all of the flux. The zeropoints posted on the WFC3 website are calculated for an infinite aperture, so when computing photometry for smaller radii, aperture corrections must be applied.\n", "\n", "The inputs below can be changed to any desired `obsmode`, with examples of alternate parameters shown as commented lines." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Detector:\n", "detectors = ['uvis1']\n", "#detectors = ['uvis1', 'uvis2'] # both UVIS chips\n", "#detectors = ['ir'] # if using IR, must update the filtnames below" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Filters:\n", "filtnames = ['f200lp','f218w','f225w','f275w','f280n','f300x', 'f336w','f343n','f350lp',\n", " 'f373n', 'f390m','f390w','f395n','f410m','f438w', 'f467m','f469n','f475w',\n", " 'f475x', 'f487n','f502n','f547m','f555w','f600lp','f606w','f621m','f625w',\n", " 'f631n', 'f645n','f656n','f657n','f658n','f665n', 'f673n','f680n','f689m',\n", " 'f763m', 'f775w','f814w','f845m','f850lp','f953n']\n", "#filtnames = ['f606w'] \n", "\n", "# For IR filters, must set detectors = ['ir'] above\n", "#filtnames = ['f098m','f105w','f110w','f125w','f126n','f127m','f128n','f130n','f132n','f139m','f140w','f153m','f160w','f164n','f167n']" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Date\n", "mjd = '55008' # WFC3/UVIS reference epoch (26Jun2009)\n", "# mjd = str(Time.now().mjd) # Time right now" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Aperture Radius\n", "aper = '6.0' # 151 pixels (infinity) [default behavior]\n", "#aper = '0.396' # 10 pixels for UVIS\n", "#aper = '0.385' # 3 pixels for IR" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 3. Basic usage for a single 'obsmode' " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The calculation of the zeropoints starts with creating a specific bandpass object. Bandpasses generally consist of at least an instrument name, detector name, and filter name, though other parameters (such as the MJD and aperture radius shown above) are optional. For example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "obsmode = 'wfc3,uvis1,f200lp'\n", "bp = stsyn.band(obsmode) # creates bandpass object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Optional parameters are supplied on the end of the basic bandpass:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "obsmode = 'wfc3,uvis1,f200lp,mjd#55008,aper#6.0'\n", "# or to use parameters above:\n", "obsmode = 'wfc3,{},{},mjd#{},aper#{}'.format(detectors[0],filtnames[0],mjd,aper)\n", "bp = stsyn.band(obsmode)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4. Computing zeropoints and other photometric properties " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the bandpass objects we can now calculate zeropoints, pivot wavelengths, and photometric bandwidths. To calculate Vegamag zeropoints, we use the Vega spectrum to calculate the flux in a given bandpass." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def calculate_values(detector, filt, mjd, aper):\n", " # parameters can be removed from obsmode as needed\n", " obsmode = 'wfc3,{},{},mjd#{},aper#{}'.format(detector, filt, mjd, aper)\n", " bp = stsyn.band(obsmode) \n", " \n", " # STMag\n", " photflam = bp.unit_response(stsyn.conf.area) # inverse sensitivity in flam\n", " stmag = -21.1 -2.5 * np.log10(photflam.value)\n", " \n", " # Pivot Wavelength and bandwidth\n", " photplam = bp.pivot() # pivot wavelength in angstroms\n", " bandwidth = bp.photbw() # bandwidth in angstroms\n", " \n", " # ABMag\n", " abmag = stmag - 5 * np.log10(photplam.value) + 18.6921\n", " \n", " # Vegamag\n", " obs = Observation(stsyn.Vega, bp, binset=bp.binset) # synthetic observation of vega in bandpass using vega spectrum\n", " vegamag = -obs.effstim(flux_unit='obmag', area=stsyn.conf.area)\n", " \n", " return obsmode, photplam.value, bandwidth.value, photflam.value, stmag, abmag, vegamag.value" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "obsmode, photplam, bandwidth, photflam, stmag, abmag, vegamag = calculate_values(detectors[0], filtnames[0], mjd, aper)\n", "\n", "# print values\n", "print('Obsmode PivotWave Photflam STMAG ABMAG VEGAMAG')\n", "print(f'{obsmode}, {photplam:.1f}, {photflam:.4e}, {stmag:.3f}, {abmag:.3f}, {vegamag:.3f}')\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 5. Iterating over multiple 'obsmodes' " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To calculate zeropoints for multiple detectors and/or filters: " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "oms, pivots, bws, pfs, st, ab, vm = [], [], [], [], [], [], []\n", "\n", "print('Obsmode PivotWave Photflam STMAG ABMAG VEGAMAG')\n", "for detector in detectors:\n", " for filt in filtnames:\n", " res = calculate_values(detector, filt, mjd, aper)\n", " obsmode, photplam, bandwidth, photflam, stmag, abmag, vegamag = res # solely for readability\n", " \n", " # print values\n", " print(f'{obsmode}, {photplam:.1f}, {photflam:.4e}, {stmag:.3f}, {abmag:.3f}, {vegamag:.3f}')\n", " \n", " oms.append(obsmode)\n", " pivots.append(photplam)\n", " bws.append(bandwidth)\n", " pfs.append(photflam)\n", " st.append(stmag)\n", " ab.append(abmag)\n", " vm.append(vegamag)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Values can also be written into an astropy table:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "tbl = Table([oms, pivots, bws, pfs, st, ab, vm], \n", " names=['Obsmode', 'Pivot Wave', 'Bandwidth', 'Photflam', 'STMag', 'ABMag', 'VegaMag'])\n", "\n", "# Just for rounding columns to smaller number of decimals\n", "for col in tbl.itercols():\n", " if col.name == 'Photflam':\n", " col.info.format = '.4e'\n", " elif col.info.dtype.kind == 'f': \n", " col.info.format = '.3f'\n", "\n", "# Show table\n", "tbl" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Write to a file\n", "tbl.write('uvis_zp_tbl.txt', format='ascii.commented_header')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 6. Creating and plotting 'total system throughput' tables" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def calculate_bands(bp, save=False):\n", " # Pass in bandpass object as bp\n", " waves = bp.waveset\n", " throughput = bp(waves)\n", " \n", " if save:\n", " tmp = Table([waves, throughput], names=['WAVELENGTH', 'THROUGHPUT'])\n", " tmp.write(','.join(bp.obsmode.modes)+'.txt', format='ascii.commented_header')\n", " \n", " return (waves, throughput)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The above function returns a tuple containing two objects, the first being an array of wavelengths, and the second being the throughput at each of those wavelengths. The result can be plotted via:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "wl, tp = calculate_bands(bp)\n", "\n", "import matplotlib.pyplot as plt\n", "\n", "fig = plt.figure(figsize=(10,5))\n", "plt.plot(wl, tp)\n", "plt.xlim(1500, 11000) \n", "plt.xlabel('Wavelength [Angstroms]')\n", "plt.ylabel('Throughput')\n", "plt.title('WFC3,UVIS1,F200LP')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To save the curve in an ascii table, simply pass the argument `save=True`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "calculate_bands(bp, save=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ls *txt" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To save curves for all obsmodes in the input list:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for det in detectors:\n", " for filt in filtnames:\n", " obsmode = 'wfc3,{},{}'.format(det, filt)\n", " bp = stsyn.band(obsmode)\n", " calculate_bands(bp, save=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ls wfc3*txt" ] } ], "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.5" } }, "nbformat": 4, "nbformat_minor": 4 }