WFC3/UVIS Filter Transformations with stsynphot#


Learning Goals#

By the end of this tutorial, you will:

  • Generate synthetic observations using synphot and stsynphot.

  • Find color terms between WFC3/UVIS filters and non-HST filters.

  • Plot bandpasses to investigate various throughputs.

Table of Contents#

Introduction
1. Imports
2. Select filters for the transformation
3. Define a spectrum
4. Select UVIS chips
5. Select magnitude systems
6. Generate outputs
7. Plot bandpasses
8. Conclusions
Additional Resources
About the Notebook
Citations

Introduction#

This notebook computes color terms between selected WFC3/UVIS filters and non-HST filters, such as Johnson-Cousins, for a user-defined reference spectrum. The terms as given are the difference between the magnitude of the spectrum in the selected non-HST filter and the corresponding UVIS filter.

This tool reproduces the methods described in section 4 of WFC3 ISR 2014-16, but will automatically use the latest available spectra and throughput tables.

stsynphot requires access to data distributed by the Calibration Data Reference System (CRDS) in order to operate. Both packages look for an environment variable called PYSYN_CDBS to find the directory containing these data.

Users can obtain these data files from the CDRS. Information on how to obtain the most up-to-date reference files (and what they contain) can be found here. An example of how to download the files with curl and set up this environment variable is presented below.

For detailed instructions on how to install and set up these packages, see the synphot and stsynphot documentation.

1. Imports#

This notebook assumes you have created the virtual environment in WFC3 notebooks’ installation instructions.

We import:

  • os for setting environment variables

  • tarfile for extracting a .tar archive

  • numpy for handling array functions

  • pandas for managing data

  • matplotlib.pyplot for plotting data

  • astropy.units and synphot.units for handling units

  • synphot and stsynphot for evaluating synthetic photometry

Additionally, we will need to set the PYSYN_CDBS environment variable before importing stsynphot. We will also create a Vega spectrum using synphot’s inbuilt from_vega() method, as the latter package will supercede this method’s functionality and require a downloaded copy of the latest Vega spectrum to be provided.

import os
import tarfile
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import astropy.units as u
import synphot.units as su
import synphot as syn
from synphot import Observation

%matplotlib inline

vegaspec = syn.SourceSpectrum.from_vega()

This section obtains the WFC3 throughput component tables for use with stsynphot. This step only needs to be done once. If these reference files have already been downloaded, this section can be skipped.

!curl -O https://archive.stsci.edu/hlsps/reference-atlases/hlsp_reference-atlases_hst_multi_everything_multi_v11_sed.tar
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0  796M    0 6064k    0     0  5356k      0  0:02:32  0:00:01  0:02:31 5352k
  4  796M    4 37.8M    0     0  17.9M      0  0:00:44  0:00:02  0:00:42 17.8M
  8  796M    8 65.2M    0     0  20.8M      0  0:00:38  0:00:03  0:00:35 20.8M
 10  796M   10 82.4M    0     0  19.8M      0  0:00:40  0:00:04  0:00:36 19.8M
 12  796M   12 98.2M    0     0  19.2M      0  0:00:41  0:00:05  0:00:36 19.7M
 13  796M   13  110M    0     0  18.1M      0  0:00:43  0:00:06  0:00:37 21.0M
 14  796M   14  119M    0     0  16.6M      0  0:00:47  0:00:07  0:00:40 16.1M
 15  796M   15  125M    0     0  15.4M      0  0:00:51  0:00:08  0:00:43 12.0M
 16  796M   16  130M    0     0  14.2M      0  0:00:55  0:00:09  0:00:46 9841k
 17  796M   17  136M    0     0  13.4M      0  0:00:59  0:00:10  0:00:49 7707k
 17  796M   17  142M    0     0  12.7M      0  0:01:02  0:00:11  0:00:51 6299k
 18  796M   18  147M    0     0  12.1M      0  0:01:05  0:00:12  0:00:53 5899k
 19  796M   19  153M    0     0  11.7M      0  0:01:08  0:00:13  0:00:55 5808k
 19  796M   19  159M    0     0  11.2M      0  0:01:10  0:00:14  0:00:56 5858k
 20  796M   20  163M    0     0  10.8M      0  0:01:13  0:00:15  0:00:58 5728k
 21  796M   21  168M    0     0  10.4M      0  0:01:15  0:00:16  0:00:59 5557k
 21  796M   21  174M    0     0  10.1M      0  0:01:18  0:00:17  0:01:01 5492k
 22  796M   22  180M    0     0   9.9M      0  0:01:20  0:00:18  0:01:02 5497k
 23  796M   23  186M    0     0  9974k      0  0:01:21  0:00:19  0:01:02 5592k
 24  796M   24  192M    0     0  9774k      0  0:01:23  0:00:20  0:01:03 5774k
 24  796M   24  198M    0     0  9602k      0  0:01:24  0:00:21  0:01:03 5980k
 25  796M   25  204M    0     0  9454k      0  0:01:26  0:00:22  0:01:04 6074k
 26  796M   26  210M    0     0  9294k      0  0:01:27  0:00:23  0:01:04 6049k
 27  796M   27  216M    0     0  9186k      0  0:01:28  0:00:24  0:01:04 6176k
 27  796M   27  221M    0     0  9046k      0  0:01:30  0:00:25  0:01:05 6103k
 28  796M   28  227M    0     0  8897k      0  0:01:31  0:00:26  0:01:05 5916k
 29  796M   29  231M    0     0  8735k      0  0:01:33  0:00:27  0:01:06 5562k
 29  796M   29  235M    0     0  8578k      0  0:01:35  0:00:28  0:01:07 5249k
 30  796M   30  238M    0     0  8402k      0  0:01:37  0:00:29  0:01:08 4615k
 30  796M   30  242M    0     0  8243k      0  0:01:38  0:00:30  0:01:08 4221k
 30  796M   30  245M    0     0  8057k      0  0:01:41  0:00:31  0:01:10 3677k
 30  796M   30  246M    0     0  7852k      0  0:01:43  0:00:32  0:01:11 3068k
 31  796M   31  247M    0     0  7652k      0  0:01:46  0:00:33  0:01:13 2455k
 31  796M   31  248M    0     0  7455k      0  0:01:49  0:00:34  0:01:15 1977k
 31  796M   31  249M    0     0  7272k      0  0:01:52  0:00:35  0:01:17 1420k
 31  796M   31  250M    0     0  7089k      0  0:01:55  0:00:36  0:01:19 1034k
 31  796M   31  250M    0     0  6916k      0  0:01:57  0:00:37  0:01:20  930k
 31  796M   31  251M    0     0  6764k      0  0:02:00  0:00:38  0:01:22  880k
 31  796M   31  252M    0     0  6619k      0  0:02:03  0:00:39  0:01:24  878k
 31  796M   31  254M    0     0  6482k      0  0:02:05  0:00:40  0:01:25  942k
 32  796M   32  255M    0     0  6355k      0  0:02:08  0:00:41  0:01:27 1082k
 32  796M   32  256M    0     0  6245k      0  0:02:10  0:00:42  0:01:28 1227k
 32  796M   32  258M    0     0  6142k      0  0:02:12  0:00:43  0:01:29 1385k
 32  796M   32  261M    0     0  6058k      0  0:02:14  0:00:44  0:01:30 1676k
 33  796M   33  263M    0     0  5975k      0  0:02:16  0:00:45  0:01:31 1911k
 33  796M   33  266M    0     0  5907k      0  0:02:18  0:00:46  0:01:32 2188k
 33  796M   33  268M    0     0  5843k      0  0:02:19  0:00:47  0:01:32 2467k
 34  796M   34  271M    0     0  5784k      0  0:02:20  0:00:48  0:01:32 2709k
 34  796M   34  274M    0     0  5728k      0  0:02:22  0:00:49  0:01:33 2827k
 34  796M   34  277M    0     0  5674k      0  0:02:23  0:00:50  0:01:33 2962k
 35  796M   35  280M    0     0  5626k      0  0:02:24  0:00:51  0:01:33 3038k
 35  796M   35  283M    0     0  5579k      0  0:02:26  0:00:52  0:01:34 3076k
 36  796M   36  287M    0     0  5536k      0  0:02:27  0:00:53  0:01:34 3153k
 36  796M   36  290M    0     0  5502k      0  0:02:28  0:00:54  0:01:34 3280k
 37  796M   37  295M    0     0  5481k      0  0:02:28  0:00:55  0:01:33 3529k
 37  796M   37  299M    0     0  5471k      0  0:02:29  0:00:56  0:01:33 3881k
 38  796M   38  305M    0     0  5480k      0  0:02:28  0:00:57  0:01:31 4459k
 39  796M   39  313M    0     0  5516k      0  0:02:27  0:00:58  0:01:29 5297k
 40  796M   40  322M    0     0  5579k      0  0:02:26  0:00:59  0:01:27 6414k
 41  796M   41  333M    0     0  5676k      0  0:02:23  0:01:00  0:01:23 7833k
 43  796M   43  346M    0     0  5808k      0  0:02:20  0:01:01  0:01:19 9589k
 45  796M   45  363M    0     0  5987k      0  0:02:16  0:01:02  0:01:14 11.4M
 47  796M   47  377M    0     0  6115k      0  0:02:13  0:01:03  0:01:10 12.7M
 49  796M   49  390M    0     0  6243k      0  0:02:10  0:01:04  0:01:06 13.8M
 50  796M   50  402M    0     0  6323k      0  0:02:08  0:01:05  0:01:03 13.7M
 52  796M   52  414M    0     0  6416k      0  0:02:07  0:01:06  0:01:01 13.4M
 53  796M   53  427M    0     0  6513k      0  0:02:05  0:01:07  0:00:58 12.7M
 55  796M   55  439M    0     0  6613k      0  0:02:03  0:01:08  0:00:55 12.6M
 56  796M   56  452M    0     0  6705k      0  0:02:01  0:01:09  0:00:52 12.3M
 58  796M   58  465M    0     0  6802k      0  0:01:59  0:01:10  0:00:49 12.7M
 60  796M   60  479M    0     0  6896k      0  0:01:58  0:01:11  0:00:47 12.9M
 61  796M   61  492M    0     0  6992k      0  0:01:56  0:01:12  0:00:44 13.1M
 63  796M   63  505M    0     0  7074k      0  0:01:55  0:01:13  0:00:42 13.0M
 65  796M   65  518M    0     0  7161k      0  0:01:53  0:01:14  0:00:39 13.1M
 66  796M   66  532M    0     0  7252k      0  0:01:52  0:01:15  0:00:37 13.2M
 68  796M   68  546M    0     0  7346k      0  0:01:50  0:01:16  0:00:34 13.4M
 70  796M   70  560M    0     0  7446k      0  0:01:49  0:01:17  0:00:32 13.6M
 72  796M   72  575M    0     0  7546k      0  0:01:48  0:01:18  0:00:30 14.1M
 74  796M   74  592M    0     0  7668k      0  0:01:46  0:01:19  0:00:27 14.8M
 76  796M   76  611M    0     0  7808k      0  0:01:44  0:01:20  0:00:24 15.7M
 79  796M   79  631M    0     0  7969k      0  0:01:42  0:01:21  0:00:21 17.1M
 81  796M   81  651M    0     0  8129k      0  0:01:40  0:01:22  0:00:18 18.2M
 84  796M   84  670M    0     0  8258k      0  0:01:38  0:01:23  0:00:15 18.8M
 85  796M   85  681M    0     0  8288k      0  0:01:38  0:01:24  0:00:14 17.6M
 86  796M   86  691M    0     0  8314k      0  0:01:38  0:01:25  0:00:13 16.0M
 88  796M   88  701M    0     0  8340k      0  0:01:37  0:01:26  0:00:11 14.0M
 89  796M   89  712M    0     0  8373k      0  0:01:37  0:01:27  0:00:10 12.0M
 90  796M   90  723M    0     0  8407k      0  0:01:36  0:01:28  0:00:08 10.6M
 92  796M   92  735M    0  
   0  8446k      0  0:01:36  0:01:29  0:00:07 10.8M
 93  796M   93  745M    0     0  8473k      0  0:01:36  0:01:30  0:00:06 10.9M
 95  796M   95  757M    0     0  8507k      0  0:01:35  0:01:31  0:00:04 11.1M
 96  796M   96  768M    0     0  8540k      0  0:01:35  0:01:32  0:00:03 11.1M
 97  796M   97  780M    0     0  8575k      0  0:01:35  0:01:33  0:00:02 11.2M
 99  796M   99  791M    0     0  8606k      0  0:01:34  0:01:34 --:--:-- 11.1M
100  796M  100  796M    0     0  8622k      0  0:01:34  0:01:34 --:--:-- 11.3M

Once the downloaded is complete, extract the file and set the environment variable PYSYN_CDBS to the path of the trds subdirectory. The next cell will do this for you, as long as the .tar file downloaded above has not been moved.

tar_archive = 'hlsp_reference-atlases_hst_multi_everything_multi_v11_sed.tar'
extract_to = 'hlsp_reference-atlases_hst_multi_everything_multi_v11_sed'
abs_extract_to = os.path.abspath(extract_to)

with tarfile.open(tar_archive, 'r') as tar:
    for member in tar.getmembers():
        member_path = os.path.abspath(os.path.join(abs_extract_to, member.name))
        if member_path.startswith(abs_extract_to):
            tar.extract(member, path=extract_to)   
        else:
            print(f"Skipped {member.name} due to potential security risk")

os.environ['PYSYN_CDBS'] = os.path.join(abs_extract_to, 'grp/redcat/trds/')

Now, after having set up PYSYN_CDBS, we import stsynphot. A warning regarding the Vega spectrum is expected here.

import stsynphot as stsyn
WARNING: Failed to load Vega spectrum from /home/runner/work/hst_notebooks/hst_notebooks/notebooks/WFC3/filter_transformations/hlsp_reference-atlases_hst_multi_everything_multi_v11_sed/grp/redcat/trds//calspec/alpha_lyr_stis_011.fits; Functionality involving Vega will be severely limited: FileNotFoundError(2, 'No such file or directory') [stsynphot.spectrum]

2. Select filters for the transformation#

Define the filters to use for computing the transformation. One filter should be a UVIS filter, and the other a non-HST filter such as a Johnson-Cousins filter.

Filter names should be input as a list of tupled strings. Each tuple represents a pair of filters to convert between, and should contain the non-HST filter as the first element, and the UVIS filter as the second.

For non-HST filters, the filter system be included in the string, separated from the filter name by a comma (e.g. 'johnson, v' or 'sdss, g'). The available non-HST filters are listed here:

System

Bands

cousins

r, i

galex

nuv, fuv

johnson

u, b, v, r, i, j, k

landolt

u, b, v, r, i

sdss

u, g, r, i, z,

stromgren

u, v, b, y

Furthermore, Johnson-Cousins filters with corresponding UVIS filters are listed here:

Johnson-Cousins Filter

UVIS Filter

U

F336W

B

F475W

V

F555W/F606W

I

F814W

A summary of the UVIS filters, with descriptions, is available in Section 6.5.1 of the WFC3 Instrument Handbook

The notebook is currently set up to return the color terms between the V and I Johnson-Cousins filters, and corresponding UVIS filters.

filter_pairs = [('johnson, v', 'f555w'), ('cousins, i', 'f814w')]

3. Define a spectrum#

Define a spectrum to get color terms for. Some common options are embedded below. A wide array of reference spectra are available for download from spectral atlases located here.

# Blackbody (5000 K)
blackbody_temperature = 5000

model = syn.models.BlackBody1D(blackbody_temperature)
source_spectrum  = syn.SourceSpectrum(model)

# Power law 
pl_index = 0

model = syn.models.PowerLawFlux1D(amplitude=flux_in, x_0=wl_in, alpha=pl_index)
source_spectrum  = syn.SourceSpectrum(model)
                   
# Load from a FITS table (e.g. a CALSPEC spectrum)
source_spectrum = syn.SourceSpectrum.from_file('/path/to/your/spectrum.fits')

Currently, the notebook is configured to use a 5000 K blackbody spectrum.

blackbody_temperature = 5000

model = syn.models.BlackBody1D(blackbody_temperature)
source_spectrum = syn.SourceSpectrum(model)

4. Select UVIS chips#

Quantum efficiency differences between the two UVIS chips mean that you must specify which chips to use for computing color terms. Simply set the chip you would like to use to True and the other to False, or set both to True if you would like coefficients for both.

use_uvis1 = True
use_uvis2 = True
chips = [use_uvis1, use_uvis2]

5. Select magnitude systems#

Select which magnitude systems you would like color terms to be provided for. Set those you would like to True and others to False.

ABMAG = True
STMAG = True
VEGAMAG = False

mags = [('ABMAG', u.ABmag, ABMAG), ('STMAG', u.STmag, STMAG),
        ('VEGAMAG', su.VEGAMAG, VEGAMAG)]

6. Generate outputs#

Generate a data frame containing the color terms for the inputs you have specified.

First, let’s define the column names for the output table, and a list to fill with table rows.

cols = ['Filter Pair', 'Chip']
rows = []

Then, append the names of magnitude systems being used.

for name, _, toggle in mags:
    if toggle:
        cols.append(f'{name} Color Term')

Next, iterate over filter pairs. For each filter pair, this loop will:

  • generate observation mode strings, bandpasses, and observations

  • calculate the color term and append it

  • append filters, chip, and color term as a row to rows

for pair in filter_pairs:
    comparison_filter, uvis_filter = pair  # Unpack filters
    filt_str = comparison_filter + ' - ' + uvis_filter

    for i, toggle in enumerate(chips):
        if not toggle:
            continue
        chip_str = 'UVIS' + str(i + 1)

        # Generate observation mode strings, bandpasses, observations
        comparison_obsmode = comparison_filter
        uvis_obsmode = 'wfc3, ' + chip_str + ', ' + uvis_filter

        comparison_bp = stsyn.band(comparison_obsmode)
        uvis_bp = stsyn.band(uvis_obsmode)

        comparison_observation = Observation(source_spectrum, comparison_bp)
        uvis_observation = Observation(source_spectrum, uvis_bp)
        row = [filt_str, chip_str]  # Append filters and chip to row

        for name, unit, toggle in mags:
            if not toggle:
                continue
            comparison_countrate = comparison_observation.effstim(
                flux_unit=unit, vegaspec=vegaspec)
            uvis_countrate = uvis_observation.effstim(
                flux_unit=unit, vegaspec=vegaspec)
            color = comparison_countrate - uvis_countrate  # Find color term
            row.append(f'{color.value:.3f}')  # Append color term

        rows.append(row)  # Append row to list of rows

Finally, generate and return the output table.

df = pd.DataFrame(rows, columns=cols)
df
Filter Pair Chip ABMAG Color Term STMAG Color Term
0 johnson, v - f555w UVIS1 -0.094 -0.025
1 johnson, v - f555w UVIS2 -0.094 -0.025
2 cousins, i - f814w UVIS1 0.005 -0.039
3 cousins, i - f814w UVIS2 0.005 -0.038

If you wish to save the output table as a .txt file, please uncomment and execute the code block below.

# df.to_csv('your/path/here.txt', sep='\t')

7. Plot bandpasses#

It can be nice to see your selected bandpass pairs plotted with each other. The cell below will generate a figure with subplots for each filter pair specified above, as well as the relevant portion of the spectrum you’ve defined, all normalized to fit on the same axes.

Note: For the purposes of these plots, the non-HST bandpass and spectrum have been scaled to the amplitude of the HST bandpass, which reflects the actual total system throughput as a function of wavelength.

fig, axs = plt.subplots(1, len(filter_pairs), sharey=True, figsize=(
    4*len(filter_pairs), 5))  # Instantiate subplots
axs[0].set_ylabel('Throughput')
for i, pair in enumerate(filter_pairs):

    f1, f2 = pair
    bp1 = stsyn.band(f1)
    bp2 = stsyn.band('wfc3, uvis1,' + f2)

    # Create wavelength array for subplot based on average bandpass wavelength and width
    avgwave = (bp1.avgwave().to(u.nm) + bp2.avgwave().to(u.nm))/2
    width = (bp1.rectwidth().to(u.nm) + bp2.rectwidth().to(u.nm))/2
    left = max((avgwave - 1.5 * width).value, 1)
    right = (avgwave + 1.5 * width).value

    wl = np.arange(left, right) * u.nm

    # Normalize curves to fit on one set of axes
    bp1_norm = bp1(wl) / np.max(bp1(wl)) * np.max(bp2(wl))
    spec_norm = source_spectrum(
        wl) / np.max(source_spectrum(wl)) * np.max(bp2(wl))

    # Plot bandpasses and spectrum on subplot
    axs[i].plot(wl, bp1_norm, ls='--', label=f1, c='tab:blue')
    axs[i].plot(wl, bp2(wl),  ls='-.', label=f2, c='tab:red')
    axs[i].plot(wl, spec_norm, label='source spectrum', c='tab:purple')
    axs[i].set_xlabel('Wavelength (nm)')
    axs[i].legend(fontsize='x-small', loc='upper right')
plt.tight_layout()
../../../_images/2819abcd5e8291a8eea4470e190ee40985796f450e7933882d520e92bf0de902.png

8. Conclusions#

Thank you for walking through this notebook. Now using WFC3 data, you should be more familiar with:

  • Generating synthetic observations using synphot and stsynphot.

  • Finding color terms between WFC3/UVIS filters and non-HST filters.

  • Ploting bandpasses to investigate various throughputs.

Congratulations, you have completed the notebook!#

Additional Resources#

Below are some additional resources that may be helpful. Please send any questions through the HST Helpdesk.

About this Notebook#

Authors: Aidan Pidgeon, Jennifer Mack; WFC3 Instrument Team

Updated on: 2021-09-13

Citations#

If you use numpy, astropy, synphot, or stsynphot for published research, please cite the authors. Follow these links for more information about citing the libraries below:


Top of Page Space Telescope Logo