WFC3/IR IMA Visualization Tools with An Example of Time Variable Background#

Learning Goals#

The main purpose of this notebook is to familiarize users with the structure of the WFC3/IR IMA files, to visualize individual reads and the difference between reads, and to plot the cumulative signal and count rate throughout the MULTIACCUM exposure. These visualization tools may be used to identify issues with the data, for example, a guidestar (GS) failure, a satellite trail in a specific read, or time variable background, which may take the form of scattered light or He I 10830 Å airglow line emission.

This notebook walks through:

  • Exploring WFC3/IR IMA Data Structure;

  • How to find and select individual reads in an IMA file;

  • How to show individual reads as images;

  • Plotting the signal ramp through subsequent reads;

  • Plotting the difference in signal between reads using two different methods.

Table of Contents#

Introduction
1. Imports
2. Downloading Data

  • 2.1 Download Example MULTIACCUM Observation

  • 2.2 WFC3/IR File Information

3. Visualizing Individual Reads of IMA Images
4. Taking the Difference Between Reads: The Cumulative Rate
5. A More Accurate Difference Between Reads: The Instantaneous Rate

6. Conclusions
Additional Resources
About this Notebook
Citations

Introduction #

Observing with the WFC3/IR MULTIACCUM Mode

As discussed in section 7.7 of the WFC3 Instrument Handbook, the only observing mode available for the WFC3/IR channel is the MULTIACCUM mode, which samples the signal multiple times as an exposure accumulates. Exposures are taken in “a sequence of non-destructive reads specified by the user from a variety of pre-defined configurations with both constant (SPARS) and increasing (STEP) time intervals between subsequent reads. At the time of each read, the accumulated charge on each pixel is recorded and this charge accumulation history for a given exposure — the ‘ramp’ — is recorded in the RAW data files.” The maximum number of reads (following the zero read) during an exposure is 15, which are collected as the signal ramps up.

Multiple readouts in the MULTIACCUM mode are advantageous for three key reasons. First, they increase the dynamic range of the image. The signal in a pixel that is saturated by the end of the exposure is recorded multiple times, including before saturation. Second, cosmic-ray events that occur throughout the exposure can be anaylzed and identified in individual reads and subsequently removed. Finally, by fitting to multiple reads, one can reduce the effective read noise in an observation.

See section 7.7 of the WFC3 Instrument Handbook for more details.

Time-Variable Background in the WFC3/IR Channel

In WFC3/IR images, the sky background may be comprised of one or more of the following components: zodiacal light, scattered light from the bright Earth limb, and He I 10830 Å airglow line emission from helium atoms excited by sunlight in the Earth’s upper atmosphere. The zodiacal light, which depends on the orientation of the target with respect to the sun, varies throughout the year but is effectively constant within a given exposure/orbit/visit. However, the scattered light and line emission components can vary within an orbit and even within a single exposure, leading to a background that varies with time. In this notebook, we will show an example of time-variable background due to Earth limb scattered light (made when HST is pointing near the bright Earth limb), which results in a spatially variable signal with the leftmost (x<400) columns of the detector being subject to background levels up to twice as bright as that on the rest of the chip.

In the following sections, we show how to identify the impacted reads. In future WFC3 Library notebooks, Correcting for Scattered Light in WFC3/IR Exposures: Using calwf3 to Exclude Bad Reads (O’Connor, in prep.) and Correcting for Scattered Light in IR Exposures: Manually Excluding Bad Reads (O’Connor, in prep.), we show how to reprocess the exposure while excluding those reads. Here, we show how to compute and plot the median background rate (e.g. the difference between IMA reads) and we compare the background in different regions of the detector.

See section 7.10 of the WFC3 Data Handbook for more details.

1. Imports #

We use the following libraries:

  • os for splitting file paths

  • numpy for handling array functions

  • matplotlib.pyplot for plotting data

  • astropy.io fits for accessing FITS files

  • astroquery for downlaoding data from MAST

We import the following module:

  • ima_visualization_and_differencing to take the difference between reads, plot the ramp, and to visualize the difference in images

import os
import numpy as np
from matplotlib import pyplot as plt
from astropy.io import fits
from astroquery.mast import Observations
import ima_visualization_and_differencing as diff

%matplotlib inline

2. Downloading Data #

2.1 Download Example MULTIACCUM Observation #

Here, we download two consecutive exposures from image association ‘ICQTBB020’ acquired in visit BB of program 14037. This visit consists of two orbits of two exposures each, and we focus on the second orbit which contains two identical images of the target (filter=F140W, SAMP-SEQ=SPARS100, NSAMP=16). The first exposure ‘icqtbbbxq’ was acquired in the first half of the orbit and is strongly contaminated by scattered light. The second exposure ‘icqtbbc0q’ was acquired during the second half of the orbit and allows us to compare what one would see in a nominal image.

When running this notebook, these dataset names may be replaced with your own observations. If running this notebook with just one observation, note that simple changes to each cell will allow you to run the notebook with just one image (these changes are suggested within each cell). We recommend that you step through this notebook first using the example observations given below.

Let’s query for the IR images using MAST, selecting both the IMA and FLT data products from the two exposures: ‘icqtbbbxq’ and ‘icqtbbc0q’.

EX_OBS = Observations.query_criteria(obs_id='ICQTBB020')
EXOBS_Prods = Observations.get_product_list(EX_OBS)
yourProd = Observations.filter_products(EXOBS_Prods, obs_id=['icqtbbbxq', 'icqtbbc0q'], extension=["_ima.fits", "_flt.fits"])
yourProd
Table masked=True length=4
obsIDobs_collectiondataproduct_typeobs_iddescriptiontypedataURIproductTypeproductGroupDescriptionproductSubGroupDescriptionproductDocumentationURLprojectprvversionproposal_idproductFilenamesizeparent_obsiddataRightscalib_level
str8str3str5str35str62str1str67str9str28str11str1str7str19str5str50int64str8str6int64
25006494HSTimageicqtbbbxqDADS IMA file - Intermediate Mult-Accum WFC3/NICMOSSmast:HST/product/icqtbbbxq_ima.fitsAUXILIARY--IMA--CALWF33.7.1 (Oct-18-2023)14037icqtbbbxq_ima.fits16826112025007139PUBLIC2
25006494HSTimageicqtbbbxqDADS FLT file - Calibrated exposure ACS/WFC3/STIS/COSSmast:HST/product/icqtbbbxq_flt.fitsSCIENCE--FLT--CALWF33.7.1 (Oct-18-2023)14037icqtbbbxq_flt.fits1658304025007139PUBLIC2
25006495HSTimageicqtbbc0qDADS IMA file - Intermediate Mult-Accum WFC3/NICMOSSmast:HST/product/icqtbbc0q_ima.fitsAUXILIARY--IMA--CALWF33.7.1 (Oct-18-2023)14037icqtbbc0q_ima.fits16826112025007139PUBLIC2
25006495HSTimageicqtbbc0qDADS FLT file - Calibrated exposure ACS/WFC3/STIS/COSSmast:HST/product/icqtbbc0q_flt.fitsSCIENCE--FLT--CALWF33.7.1 (Oct-18-2023)14037icqtbbc0q_flt.fits1658304025007139PUBLIC2
Observations.download_products(yourProd, mrp_only=False, cache=False)
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HST/product/icqtbbbxq_ima.fits to ./mastDownload/HST/icqtbbbxq/icqtbbbxq_ima.fits ...
 [Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HST/product/icqtbbbxq_flt.fits to ./mastDownload/HST/icqtbbbxq/icqtbbbxq_flt.fits ...
 [Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HST/product/icqtbbc0q_ima.fits to ./mastDownload/HST/icqtbbc0q/icqtbbc0q_ima.fits ...
 [Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:HST/product/icqtbbc0q_flt.fits to ./mastDownload/HST/icqtbbc0q/icqtbbc0q_flt.fits ...
 [Done]
Table length=4
Local PathStatusMessageURL
str47str8objectobject
./mastDownload/HST/icqtbbbxq/icqtbbbxq_ima.fitsCOMPLETENoneNone
./mastDownload/HST/icqtbbbxq/icqtbbbxq_flt.fitsCOMPLETENoneNone
./mastDownload/HST/icqtbbc0q/icqtbbc0q_ima.fitsCOMPLETENoneNone
./mastDownload/HST/icqtbbc0q/icqtbbc0q_flt.fitsCOMPLETENoneNone

2.2 WFC3/IR File Information #

The figure below shows the WFC3/IR file structure corresponding to Figure 2.4 of the Data Handbook. Note that for WFC3/IR data, each read or image set (IMSET) consists of five data arrays: SCI, ERR, DQ, SAMP, TIME. Consecutive MULTIACCUM readouts are stored in reverse chronological order, with [SCI,1] corresponding to the final, cumulative exposure.

Diagram of WFC3/IR Data Format, consisting of four columns representing each IMA read, made up of a science array, an error array, DQ array, and integration time.

The table below lists the IMSET, SAMPNUM, and SAMPTIME for a WFC3/IR SPARS100 exposure, modified from Section 7.7 of the Instrument Handbook. Note that the image header keyword NSAMP reports a value of 16, but there are actually 15 science reads in the IMA file, following the 0th read (which has an exposure time of 0). While NSAMP keyword is reported in the primary header (extension 0), the SAMPNUM and SAMPTIME keywords may be found in the science header of each read, and these report the read (IMSET) number and the cumulative exposure time of each respective read.

This table is similar to Table 7.7, except that the column labelled NSAMP in the handbook is really the SAMPNUM. Note that we have added a row at the top of the table to highlight that IMSET [SCI,16] corresponds to the 0th read.

Table detailing the relationship between 'IMSET', SAMPNUM, and integration time for successive reads in an WFC3/IR image taken at a SPARS100 sample sequence.

3. Visualizing Individual Reads of IMA Images#

Next, let’s check out the file structure of our WFC3/IR IMA FITS files. We define the paths to our images here.

ima_scattered = 'mastDownload/HST/icqtbbbxq/icqtbbbxq_ima.fits'
flt_scattered = 'mastDownload/HST/icqtbbbxq/icqtbbbxq_flt.fits'
ima_nominal = 'mastDownload/HST/icqtbbc0q/icqtbbc0q_ima.fits'
flt_nominal = 'mastDownload/HST/icqtbbc0q/icqtbbc0q_flt.fits'

image = fits.open(ima_scattered)
image.info()
Filename: mastDownload/HST/icqtbbbxq/icqtbbbxq_ima.fits
No.    Name      Ver    Type      Cards   Dimensions   Format
  0  PRIMARY       1 PrimaryHDU     266   ()      
  1  SCI           1 ImageHDU        81   (1024, 1024)   float32   
  2  ERR           1 ImageHDU        43   (1024, 1024)   float32   
  3  DQ            1 ImageHDU        35   (1024, 1024)   int16   
  4  SAMP          1 ImageHDU        30   ()      
  5  TIME          1 ImageHDU        30   ()      
  6  SCI           2 ImageHDU        81   (1024, 1024)   float32   
  7  ERR           2 ImageHDU        43   (1024, 1024)   float32   
  8  DQ            2 ImageHDU        35   (1024, 1024)   int16   
  9  SAMP          2 ImageHDU        30   ()      
 10  TIME          2 ImageHDU        30   ()      
 11  SCI           3 ImageHDU        81   (1024, 1024)   float32   
 12  ERR           3 ImageHDU        43   (1024, 1024)   float32   
 13  DQ            3 ImageHDU        35   (1024, 1024)   int16   
 14  SAMP          3 ImageHDU        30   ()      
 15  TIME          3 ImageHDU        30   ()      
 16  SCI           4 ImageHDU        81   (1024, 1024)   float32   
 17  ERR           4 ImageHDU        43   (1024, 1024)   float32   
 18  DQ            4 ImageHDU        35   (1024, 1024)   int16   
 19  SAMP          4 ImageHDU        30   ()      
 20  TIME          4 ImageHDU        30   ()      
 21  SCI           5 ImageHDU        81   (1024, 1024)   float32   
 22  ERR           5 ImageHDU        43   (1024, 1024)   float32   
 23  DQ            5 ImageHDU        35   (1024, 1024)   int16   
 24  SAMP          5 ImageHDU        30   ()      
 25  TIME          5 ImageHDU        30   ()      
 26  SCI           6 ImageHDU        81   (1024, 1024)   float32   
 27  ERR           6 ImageHDU        43   (1024, 1024)   float32   
 28  DQ            6 ImageHDU        35   (1024, 1024)   int16   
 29  SAMP          6 ImageHDU        30   ()      
 30  TIME          6 ImageHDU        30   ()      
 31  SCI           7 ImageHDU        81   (1024, 1024)   float32   
 32  ERR           7 ImageHDU        43   (1024, 1024)   float32   
 33  DQ            7 ImageHDU        35   (1024, 1024)   int16   
 34  SAMP          7 ImageHDU        30   ()      
 35  TIME          7 ImageHDU        30   ()      
 36  SCI           8 ImageHDU        81   (1024, 1024)   float32   
 37  ERR           8 ImageHDU        43   (1024, 1024)   float32   
 38  DQ            8 ImageHDU        35   (1024, 1024)   int16   
 39  SAMP          8 ImageHDU        30   ()      
 40  TIME          8 ImageHDU        30   ()      
 41  SCI           9 ImageHDU        81   (1024, 1024)   float32   
 42  ERR           9 ImageHDU        43   (1024, 1024)   float32   
 43  DQ            9 ImageHDU        35   (1024, 1024)   int16   
 44  SAMP          9 ImageHDU        30   ()      
 45  TIME          9 ImageHDU        30   ()      
 46  SCI          10 ImageHDU        81   (1024, 1024)   float32   
 47  ERR          10 ImageHDU        43   (1024, 1024)   float32   
 48  DQ           10 ImageHDU        35   (1024, 1024)   int16   
 49  SAMP         10 ImageHDU        30   ()      
 50  TIME         10 ImageHDU        30   ()      
 51  SCI          11 ImageHDU        81   (1024, 1024)   float32   
 52  ERR          11 ImageHDU        43   (1024, 1024)   float32   
 53  DQ           11 ImageHDU        35   (1024, 1024)   int16   
 54  SAMP         11 ImageHDU        30   ()      
 55  TIME         11 ImageHDU        30   ()      
 56  SCI          12 ImageHDU        81   (1024, 1024)   float32   
 57  ERR          12 ImageHDU        43   (1024, 1024)   float32   
 58  DQ           12 ImageHDU        35   (1024, 1024)   int16   
 59  SAMP         12 ImageHDU        30   ()      
 60  TIME         12 ImageHDU        30   ()      
 61  SCI          13 ImageHDU        81   (1024, 1024)   float32   
 62  ERR          13 ImageHDU        43   (1024, 1024)   float32   
 63  DQ           13 ImageHDU        35   (1024, 1024)   int16   
 64  SAMP         13 ImageHDU        30   ()      
 65  TIME         13 ImageHDU        30   ()      
 66  SCI          14 ImageHDU        81   (1024, 1024)   float32   
 67  ERR          14 ImageHDU        43   (1024, 1024)   float32   
 68  DQ           14 ImageHDU        35   (1024, 1024)   int16   
 69  SAMP         14 ImageHDU        30   ()      
 70  TIME         14 ImageHDU        30   ()      
 71  SCI          15 ImageHDU        81   (1024, 1024)   float32   
 72  ERR          15 ImageHDU        43   (1024, 1024)   float32   
 73  DQ           15 ImageHDU        35   (1024, 1024)   int16   
 74  SAMP         15 ImageHDU        30   ()      
 75  TIME         15 ImageHDU        30   ()      
 76  SCI          16 ImageHDU        81   (1024, 1024)   float32   
 77  ERR          16 ImageHDU        43   (1024, 1024)   float32   
 78  DQ           16 ImageHDU        35   (1024, 1024)   int16   
 79  SAMP         16 ImageHDU        30   ()      
 80  TIME         16 ImageHDU        30   ()      

As we can see, the IMA contains 16 science (SCI) extensions or IMSETS, recorded in reverse chronological order in the file. For this observation, the “0th” read corresponds to the extension 76 or the 16th science extenstion, e.g. [SCI,16]. In the cells below, we show how to query the NSAMP and SAMPNUM keywords in the image headers.

prihdr = image[0].header
NSAMP = prihdr['NSAMP']
print(f'The total number of reads (including the 0th) is {NSAMP}.')
The total number of reads (including the 0th) is 16.
sci16hdr = image['SCI', 16].header
SAMPNUM_sci16 = sci16hdr['SAMPNUM']
SAMPTIME_sci16 = sci16hdr['SAMPTIME']
print(f'For sample number {SAMPNUM_sci16}, the exposure time is {SAMPTIME_sci16}s.')
For sample number 0, the exposure time is 0.0s.
sci1hdr = image['SCI', 1].header
SAMPNUM_sci1 = sci1hdr['SAMPNUM']
SAMPTIME_sci1 = sci1hdr['SAMPTIME']
print(f'For sample number {SAMPNUM_sci1}, the exposure time is {SAMPTIME_sci1:.3f}s.')

image.close()
For sample number 15, the exposure time is 1402.937s.

The 0th read [SCI,16] is taken at 0 seconds, while the 1st read [SCI,15] is taken just a few seconds after exposure start. Since it takes a finite time (2.93 sec) to read the full array, this short read represents the time delay between reading the first and last pixel. The rest of the reads are then taken at the time interval specified by the STEP or SPARS sequence. Here, we have chosen a dataset with SPARS100, which has a time interval of 100 seconds between reads.

Let’s compare the final read of the IMA and the corresponding FLT product for each dataset.

fig = plt.figure(figsize=(30, 30))
rows = 2
columns = 2
files = [ima_scattered, flt_scattered, ima_nominal, flt_nominal]

# If only analyzing one image, please remove the second ima,flt pair from the list
subplot_titles = ['scattered', 'nominal']

for i, file in enumerate(files):
    path, filename = os.path.split(file)

    with fits.open(file) as image:
        ax = fig.add_subplot(rows, columns, i + 1)
        title = f'{filename}, {subplot_titles[i//2]}'
        ax.set_title(title, fontsize=20)

        # Please change the vmin and vmax values to fit your own data
        vmin, vmax = (0.25, 1.7) if i < 2 else (0.5, 1.2)
        im = ax.imshow(
            image['SCI', 1].data, origin='lower', cmap='Greys_r', vmin=vmin, vmax=vmax
        )
        plt.colorbar(im, ax=ax)

plt.subplots_adjust(bottom=0.2, right=0.5, top=0.5)
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=10)
../../../_images/fe28cee25ef1ee168fa5edf686e8e0b77f0ea1591a370f1b4aea5a8857d19c25.png

Here, we see our target field. In the top row, we can see the scattered light in dataset ‘icqtbbbxq’ affecting the left side of both the IMA and FLT product. In the bottom row, we see the nominal IMA and FLT images for dataset ‘icqtbbc0q’.

Note that FLT images differ from IMA images in that they have had cosmic rays removed by the calwf3 pipeline via the CRCORR step which performs ‘up-the-ramp’ fitting.

To visually inspect each read of the IMA image, we can use the following snippet of code to create a multi-panel display. Each panel is shown with the same scale in electrons/second (e-/s) to highlight the increasing signal-to-noise in each successive read of the MULTIACCUM exposure. Here, we use the read_wfc funtion found in ima_visualization_and_differencing.py to grab the IMA science data from all reads as a data cube and the integration time as an array.

For a second tutorial on visualizing reads of the MULTIACCUM exposure, see the “IMA Viewer” notebook (Marinelli, in prep.) on the WFC3 Library GitHub. This notebook allows the user to create gifs looping through reads as the signal accumulates, which can be useful for quickly diagnosing any issues with the data.

try:
    diff.plot_ima_subplots(ima_filename=ima_scattered, vmin=0, vmax=2.2)

except FileNotFoundError:
    print("No file by this name found")
../../../_images/a671415bd55cdb68d6a552f7bac78d911b17b95ddb941289aeb208972113305f.png

Above, we see scattered light in every read in the cumulative exposure. In reality (as we will see later in this notebook), the scattered light is present only during the first few reads of the exposure. Because we are plotting reads with an accumulating signal, we see the scattered light affecting all reads of the IMA, even when the scattered light is no longer present. We will see this more clearly when visualizing the difference between reads.

Conversely, when we show individual reads from the nominal IMA file, we see no scattered light (as seen below).

try:
    diff.plot_ima_subplots(ima_filename=ima_nominal, vmin=0, vmax=2)

except FileNotFoundError:
    print("No file by this name found")
../../../_images/d862abbfc4c02a1c7a8bf5d6e11b7dddfbe4626723b6a83554bff4d26bd9698c.png

To get a better sense of how the MULTIACCUM method works, we can plot the median signal accumulation in electrons up the ramp for both images. The median value works well for sparse fields where the majority of the pixels are sky.

fig = plt.figure(figsize=(10, 8))

ima_files = [ima_scattered, ima_nominal] 
# If only using one image, please remove the extraneous image from this list 

marker_select = ['o', 's']
color_select = ['black', 'C0']
plt.rcParams.update({'font.size': 15})
for i, ima in enumerate(ima_files):
    path, filename = os.path.split(ima)

    cube, integ_time = diff.read_wfc3(ima)
    median_fullframe = np.nanmedian(cube, axis=(0, 1))

    plt.plot(integ_time[1:], median_fullframe[1:]*integ_time[1:],
             marker=marker_select[i], markersize=8, 
             color=color_select[i], label=filename)
    plt.legend()
plt.grid()
plt.xlabel('Integ. Time (s)', fontsize=15)
plt.ylabel('electrons', fontsize=15)
plt.rc('xtick', labelsize=15) 
plt.rc('ytick', labelsize=15) 
plt.grid(visible=True)
_ = plt.title("Comparison of Signal Accumulation Ramp in Nominal vs. Scattered Light Images", fontsize=15)
../../../_images/4235a8299046ee912230dd162fbf29e8bc11e4cb63fcbae23aa881db96c08b5a.png

For dataset ‘icqtbbc0q’ (blue), we see the background signal accumulating linearly with time, whereas for dataset ‘icqtbbbxq’ (black), we see a non-linear background in the first portion of the exposure. ‘icqtbbbxq’ becomes linear in the second portion of the exposure and has the same slope as the nominal exposure.

Next we compare sky values in different regions of the detector (left side, right side, and full frame). If you would like to specify your own regions for the left and right sides of your image, you can change the “lhs_region” and “rhs_region” parameters. Each region must be specified as a dictionary including the four “corners” (x0, x1, y0, and y1) of the region you would like to select. You may want to avoid the edges of the detector which have a large number of bad pixels and higher flat field errors.

Here we compare the full frame ramp for each image with the ramp from the left and right sides of the detector. We compute the median signal from the left side, right side, and full frame image using the get_median_fullframe_lhs_rhs function from the ima_visualization_and_differencing.py module.

fig = plt.figure(figsize=(50, 20))
fig
rows = 1
columns = 2
ima_files = [ima_scattered, ima_nominal] 
# If only using one image, please remove the extraneous image from this list 

subplot_titles = ['scattered', 'nominal']

lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}

plt.rcParams.update({'font.size': 40})

for i, ima in enumerate(ima_files):

    path, filename = os.path.split(ima)

    cube, integ_time = diff.read_wfc3(ima)

    median_fullframe, median_lhs, median_rhs = diff.get_median_fullframe_lhs_rhs(cube, 
                                                                                 lhs_region=lhs_region, 
                                                                                 rhs_region=rhs_region)
    
    ax = fig.add_subplot(rows, columns, i+1)
    ax.plot(integ_time[1:], median_fullframe[1:]*integ_time[1:], 's', 
            markersize=25, label='Full Frame',  color='black')
    
    ax.plot(integ_time[1:], median_lhs[1:]*integ_time[1:], '<', 
            markersize=20, label='LHS', color='C1')
    
    ax.plot(integ_time[1:], median_rhs[1:]*integ_time[1:], '>', 
            markersize=20, label='RHS', color='C2')
    
    ax.set_ylim(0, 1800)
    ax.grid()
    ax.set_xlabel('Integ. Time (s)')
    ax.set_ylabel('electrons')
    ax.legend(loc=0)
    _ = ax.set_title(f'{filename}, {subplot_titles[i]}', fontsize=40)
    ax.tick_params(axis="x", labelsize=30) 
    ax.tick_params(axis="y", labelsize=30) 
../../../_images/a527a6048054ae3c17e40025e3790778975b2cff3606927bb9662358152f6755.png

The left panel shows the observation affected by scattered light. By comparing the signal from the left side (orange triangles) and right side (green triangles) of our image, we see that the left side is brighter than the right and that the difference in total counts between the two sides is changing over the exposure. In this case, the difference between the two sides of the image is due to scattered light which varies spatially across the detector. We know the time-variable component is only due to Earth limb scattered light because this filter (F140W) is not affected by the He I 10830 Å airglow line emission (see section 7.10.2 of the WFC3 Data Handbook). In the following sections, we will identify the impacted reads by looking at the difference in count rates between each read.

The right panel shows the ramp plot for the nominal exposure, and we see that the signal from the left side, right side, and full frame are nearly identical.

Note that, in an image with an extended object, there may be a spatial dependence in the ramp plots (e.g. the right side may be higher than the left), but the slope of the ramp would be linear with time.

4. Taking the Difference Between IMA Reads: The Cumulative Rate #

Our first method of taking the difference between reads is as simple as subtracting each read from the one before, e.g. \(\mu\) = [SCI,15]-[SCI,14], [SCI,14]-[SCI,13],… where \(\mu\) represents the median difference. In the panels below, we now plot the the ramps in units of count rate (e-/s) in order to see how the background changes through the exposure. We use the compute_diff_imas function from the ima_visualization_and_differencing.py module, taking the cumulative difference between reads as described above, and the plot_ramp function from the module, which plots the median difference in count rate from the left side, right side, and full frame image.

(Note that we exclude the 0th read [SCI,16] in our difference calculations.)

# If only using one image, please remove the extraneous image from this list 
lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}
diff.plot_ramp_subplots(ima_files=[ima_scattered, ima_nominal], 
                        difference_method='cumulative', 
                        exclude_sources=False, 
                        ylims=[-0.3, 0.3], 
                        lhs_region=lhs_region, 
                        rhs_region=rhs_region)
../../../_images/e74a418f04774b77701b41de04faecbdfbb96a6c5a713dca75c61b65f9ec38e3.png

The left panel shows a large contribution from scattered light on the left side of the image (orange triangles) during the first portion of the exposure. This difference approaches zero toward the end of the exposure. The right side of the image also has a slighlty elevated count rate early in the exposure, but not as extreme as the left side.

The right panel shows that the difference in count rate is effectively zero for the nominal image, as expected.

Note that the first data point in both plots has a very large error because we are subtracting from the 1st read (~2.9 seconds), which has very little signal and large errors.

To visualize the excess signal in two dimensions, lets make a panel plot of the differences plotted above. First, we will show the image affected by time-variable background which shows the expected spatial and time variation due to scattered light. Note that each panel is plotted with a unique zscale to highlight large changes in the signal rate with time. We use the panel_plot function from the ima_visualization_and_differencing.py module.

try:
    lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
    rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}
    diff.plot_ima_difference_subplots(ima_filename=ima_scattered, 
                                      difference_method='cumulative', 
                                      lhs_region=lhs_region, 
                                      rhs_region=rhs_region)
    
except FileNotFoundError:
    print("No file by this name found")
../../../_images/41f937dbf9dcbe2396ea6702f0462cef6548bf55fda8409bf860a1ee9acae673.png

Above each panel, we print the median difference \(\mu\) in the count rate over the entire image . Below each panel, we list the IMSET difference, along with the time interval between the two IMSETs.

The statistics in orange (on the left and right side of each panel) give the median rate and standard deviation of each side of the image, respectively. The value in green ‘delta’ is the difference between the left and right side of the image. The value in white “Ratio” gives the ratio of the median difference in orange for the left versus the right side.

Note that, because we took the simple difference in reads, the sources are not visible. This leaves us with only the sky component, making it easy to identify the time-variable background and whether it is due to scattered light or Helium emission. However, since we’ve subtracted off the first read, we lose any information about the background level at the beginning of the exposure where the scattered light was the highest in this example.

We see a large difference in count rate between the two sides of the image in the earlier reads. This difference decreases with time during the exposure because the scattered light is no longer present in later reads.

Next, lets look at the difference images for the nominal exposure.

try:
    lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
    rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}
    diff.plot_ima_difference_subplots(ima_filename=ima_nominal, 
                                      difference_method='cumulative', 
                                      lhs_region=lhs_region, 
                                      rhs_region=rhs_region)

except FileNotFoundError:
    print("No file by this name found")
../../../_images/ecc0b6b0a31e539a21fc8b61ffcd767e50a5c82fe12b0b1572403745dd02e79d.png

As we expect, the differences images are blank (with the exception of a speckled pattern showing cosmic rays and differences in noise between reads). Both ‘delta’(\(\Delta\)) and \(\mu\) are effectively zero in this nominal image. The ratio, in this case, is less useful becuase the signal differences between left and right are close to zero.

5. A More Accurate Difference Between Reads: The Instantaneous Rate #

Here we implement a different technique to examine the count rate difference between consecutive reads. In this case, we first convert from count rate (e-/s) back to counts (e-) before taking the difference, as shown in equation 3 from WFC3 ISR 2018-05.

Instantaneous Difference Equation

One advantage of this method is that it does not remove information about the signal levels at the beginning of the exposure, as in the prior method. Thus the ramp plot below shows a median rate of ~1.5 e-/s for the first two differences instead of ~zero.

# If only using one image, please remove the extraneous image from this list 
lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}
diff.plot_ramp_subplots(ima_files=[ima_scattered, ima_nominal], 
                        difference_method='instantaneous', 
                        exclude_sources=True, 
                        ylims=[0.5, 2.5], 
                        lhs_region=lhs_region, 
                        rhs_region=rhs_region)
../../../_images/945111c541a993d22670f60faee6462d97d9065764c49292509b35e5a4b1ce29.png

In our nominal exposure (right), we see a constant background due to zodiacal light at a level of ~0.9e-/s throughout. For our scattered light exposure (left), we see the same zodiacal light at a level of ~0.9e-/s in later reads, with the scattered light component affecting the first several reads where the median count rate for the left side (orange triangles) is larger than the right side (green triangles).

In the panel plot (below), we see that sources (small galaxies) are visible in the difference images using this new method, whereas in the cumulative difference method they are not. Note that this may complicate the analysis of the spatial background (e.g. left versus right) for images with extended targets, such as large galaxies. In this case, users may wish to adjust the regions of the detector used for the ramp plots. We therefore recommend inspecting both the panel plots as well as the ramp fits for diagnosing any issues with the data.

try:
    lhs_region = {"x0": 50, "x1": 250, "y0": 100, "y1": 900}
    rhs_region = {"x0": 700, "x1": 900, "y0": 100, "y1": 900}
    diff.plot_ima_difference_subplots(ima_filename=ima_scattered, 
                                      difference_method='instantaneous', 
                                      lhs_region=lhs_region, 
                                      rhs_region=rhs_region)

except FileNotFoundError:
    print("No file by this name found")
../../../_images/71ec2a86a1332b02774ff8387f05f318ab8291e4fa1d013185018b9374557015.png

In this figure, we see that the ratio of instantaneous rate for the left versus right side of the image is ~1.0 for all but the first few reads.

In a subsequent notebook, Correcting for Scattered Light in IR Exposures by Reprocessing with Calwf3 (O’Connor, in prep.), we show how to exclude these specific reads from the exposure and reprocess the image with calwf3. For this dataset, we exlude the first 6 reads, where the ratio is greater than 1.1 e-/s. While this reduces the total exposure from 1403 to 903 seconds, it removes the spatial component from the sky background and allows for a more accurate ‘up-the-ramp’ fit with calwf3.

In a separate notebook, Correcting for Scattered Light in IR Exposures by Manually Removing Bad Data(O’Connor, in prep.), we correct the final image product by manually removing bad reads from the IMA file, again exluding reads where the ratio is greater than 1.1 e-/s.

For comparison, we show the difference images for the nominal exposure (below) which do not show any scattered light artifacts.

try:
    diff.plot_ima_difference_subplots(ima_filename=ima_nominal, 
                                      difference_method='instantaneous', 
                                      lhs_region=lhs_region, 
                                      rhs_region=rhs_region)
    
except FileNotFoundError:
    print("No file by this name found")
../../../_images/33fc20c9e3506fb7effde53ce9efc2ed304ad9085a40475bf586387f21c61129.png

6. Conclusions #

Congratulations, you have completed the notebook.

You should now be familiar with:

  • How to find and select individual reads in an IMA file

  • How to display individual reads

  • How to plot the signal accumulation ramp of a WFC3/IR IMA file

  • How to plot the difference in signal between reads using two different methods

This notebook can be used to help identify issues with WFC3/IR images, for example time variable backgrounds. To correct for scattered light background in IR exposures, please see the subsequent notebooks Correcting for Scattered Light in WFC3/IR Exposures: Using calwf3 to Exclude Bad Reads (O’Connor, in prep.) and Correcting for Scattered Light in IR Exposures: Manually Excluding Bad Reads (O’Connor, in prep.), which makes use of the same dataset highlighted in this tutorial.

For a tutorial on how to correct time-variable background due to the He I 10830 Å airglow line background, which has no spatial signature, please see the notebook Correcting for Helium Line Emission Background in IR Exposures using the “Flatten-Ramp” Technique.

Additional Resources #

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

About this Notebook #

Authors:

  • Anne O’Connor, WFC3 Instrument

  • Harish Khandrika, WFC3 Instrument

  • Jennifer Mack, WFC3 Instrument

  • Annalisa Calamida, WFC3 Instrument

Updated On: 2023-05-05

Citations #

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

If you use this notebook, or information from the WFC3 Data Handbook, Instrument Handbook, or WFC3 ISRs for published research, please cite them:


Top of Page Space Telescope Logo