WFC3/UVIS Image Processing of the Bubble Nebula

2016-05-03

Roberto J. Avila (avila@stsci.edu)
Research and Instrument Analyst
Space Telescope Science Institute
3700 San Martin Dr., Baltimore, MD 21218

Observations

The Hubble Heritage Team took new observations of the Bubble Nebula on February 24-20 2016. These observations took 4 tiles in a 2x2 mosaic using three WFC3/UVIS narrowband filters (Figure 1). Parallel observations with the ACS/WFC were also taken but using only 2 narrowband filters. For more details on the observing strategy, see the proposal GO/DD-14471, PI: Zolt Levay,. Table 1 summarizes the observations and figure 1 shows the pointings on the sky.

_images/footprints.png

Figure 1 - Footprints on the sky of the two instruments used on this program. Blue is WFC3/UVIS and purple is ACS/WFC. Image produced using the Aladdin software.

Table 1 - Summary of observations.
Data set name Detector Filter Exposure per image N images per tile N tiles Total exposure (seconds)
hlsp_heritage_hst_wfc3-uvis_bubble_nebula_f502n_v1_drc.fits WFC3/UVIS F502N 650sec 3 4 7800
hlsp_heritage_hst_wfc3-uvis_bubble_nebula_f656n_v1_drc.fits WFC3/UVIS F656N 500sec 3 4 6000
hlsp_heritage_hst_wfc3-uvis_bubble_nebula_f658n_v1_drc.fits WFC3/UVIS F658N 1200sec 3 4 14000

Calibration

The data products were downloaded from MAST in FLC format. These images have been bias, dark and flat corrected. In addition, MAST applies charge transfer efficiency (CTE) correction to the images. The UVIS products went through an additional crosstalk correction step using the crosstalk_correct_wfc3.pro software provided by the WFC3 team [1].

One of the FLC images had a satellite trail that needed to be masked. We created a region file using DS9 and then we applied the mask to the DQ array using the pyregion [2] module and some astropy [3] tools.

import pyregion
from astropy.io import fits

hdu = fits.open('id3b02ofq_flc.fits',mode='update')
reg = pyregion.open('satmask02of.reg').as_imagecoord(hdu[6].header)
mask = reg.get_mask(shape=(2051,4096))
hdu[6].data[mask]|=8
hdu.close()

Alignment

Because the different visits have little overlap and there are few sources in the field, the alignment strategy is more complex than simply aligning all the images to each other. The adopted strategy for aligning the images is to create a mosaic using one filter and then align the rest of the individual exposures to that mosaic. The first mosaic is produced by aligning the exposure within a visit to each other. Then, a drizzled image is made for each tile. The drizzled products are aligned to each other and the WCS solutions propagated back to the individual exposures. The entire set of images for that filter can then be drizzled into a single mosaic. The individual exposures for the other two filters can be aligned to the mosaic, without having to align them to each other. The following is a detailed description of this entire process.

Making the reference mosaic

We began the process by aligning the images in the F658N filter. The exposures in the each visit were aligned using the Drizzlepac [4] task tweakreg. The tweakreg task generates source catalogs used for alignment. In order to produce clean catalogs, we modified some of the source finding parameters. In particular, use_sharp_round and dqbits help eliminate cosmic rays and hot pixels from the source catalogs.

After aligning the visits, a drizzled image was made for each using the astrodrizzle task in Drizzlepac. For this drizzle run, we used the parameters from the mdriztab.

Note

The commands shown in these code boxes don’t list all the available parameters for these tasks. Any parameters not listed are left as default. For details and instructions on how to use these tasks please consult the Drizzlepac help pages.

The images taken with the reference filter were moved to their own directory before the following commands were executed in python.

from drizzlepac.tweakreg import TweakReg as tweak
from drizzlepac.astrodrizzle import AstroDrizzle as adriz

imagefindparams = {'peakmin':1000,'peakmax':70000,'use_sharp_round':True,'dqbits':0}

tweak('id3b01*flc.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='intravisit',sigma=2.5,interactive=False,imagefindcfg=imagefindparams)
tweak('id3b02*flc.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='intravisit',sigma=2.5,interactive=False,imagefindcfg=imagefindparams)
tweak('id3b03*flc.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='intravisit',sigma=2.5,interactive=False,imagefindcfg=imagefindparams)
tweak('id3b04*flc.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='intravisit',sigma=2.5,interactive=False,imagefindcfg=imagefindparams)

adriz('id3b01*flc.fits',output='f658n_v1',mdriztab=True,in_memory=True)
adriz('id3b02*flc.fits',output='f658n_v2',mdriztab=True,in_memory=True)
adriz('id3b03*flc.fits',output='f658n_v3',mdriztab=True,in_memory=True)
adriz('id3b04*flc.fits',output='f658n_v4',mdriztab=True,in_memory=True)

We then ran tweakreg to align visit 2 to visit 1, and visit 4 to visit 3. For these tweakreg runs we used our own clean source catalogs that were fed to the task via the catfile keyword. After aligning the pair of visits we ran the tweakback task on the two drizzled products whose headers were updated (visits 2 & 4) to propagate the new solutions back to the individual exposures. After that we made made two drizzled products, one with visits 1 and 2 and one with visits 3 and 4.

from drizzlepac import tweakback

tweak('f658n_v[12]*sci.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='mosaic',catfile='catfile.list',minobj=6)
tweak('f658n_v[34]*sci.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='mosaic',catfile='catfile.list',minobj=6)
tweakback.tweakback('f658n_v2_drc_sci.fits')
tweakback.tweakback('f658n_v4_drc_sci.fits')

adriz('id3b0[12]*flc.fits',output='f658n_v12',mdriztab=True,in_memory=True)
adriz('id3b0[34]*flc.fits',output='f658n_v34',mdriztab=True,in_memory=True)

Once again, using our own clean catalogs, we used tweakreg to align the two drizzled images together. After aligning them, we used tweakback to propagate the results back to the FLC exposures. After the alignment process is finished, we drizzled the 4 tiles together to make a single mosaic. To make this mosaic we set skymethod=’match’ to ensure the sky across all four tiles matches up. This method matches the sky using only the pixels that the tiles in question have in common. This is the mosaic used to align the rest of the filters, but it is not the final drizzled product. There will be a final round of drizzling once all the images are aligned.

tweak('f658n_v[13][24]*sci.fits',writecat=False,clean=True,runfile='',updatehdr=True,wcsname='finalmosaic',catfile='catfile.list')
tweakback.tweakback('f658n_v12_drc_sci.fits')
tweakback.tweakback('f658n_v34_drc_sci.fits')

adriz('i*flc.fits',output='f658n_ref',runfile='',context=False,in_memory=True,skymethod='match',driz_sep_bits=2400,final_pixfrac=0.8,final_bits=96,final_units='counts')

Align F502N and F656N to reference

To align the remaining filters we first create a source catalog from the last image that we created (f658n_ref_drc_sci.fits) and clean up any unwanted artifacts. We used tweakreg to align the rest of the individual exposures, using f658n_ref_drc_sci.fits and its catalog as reference. We once again made use of the imagefindparams to help make clean catalogs from the input images. The file inputlist is a listing of the individual FLC files for the other two filters.

imagefindparams = {'peakmin':500,'peakmax':80000,'use_sharp_round':True,'dqbits':0}

tweak('@inputlist',refimage='f658n_ref_drc_sci.fits',writecat=False,clean=True,interactive=False,runfile='',updatehdr=True,wcsname='finalmosaic',refcat='refcat.coo',refxyunits='pixels',searchrad=3.0,ylimit=0.5,imagefindcfg=imagefindparams)

Drizzling

As we worked through the different drizzling iterations, it was necessary to reset the sky values in the image headers to zero. This is because the different algorithms used in the skymethod parameter use different ways of accounting for the sky (either applying an absolute value or a delta). We used the code below to reset the sky when necessary.

import glob
from astropy.io import fits

imlist = glob.glob('i*flc.fits')

for im in imlist:

  fits.setval(im,'mdrizsky',value='0.',ext=1)
  fits.setval(im,'mdrizsky',value='0.',ext=4)

Drizzling a mosaic like this one takes some special consideration. Because there is no place in the entire mosaic where the background is zero, one cannot drizzle all the images in a filter together at once. Doing this causes bad cosmic ray rejection because of the different sky levels in each tile. We therefore chose to drizzle pairs of tiles to minimize the problems with cosmic ray rejection and get our DQ masks right. We drizzled tiles 1 and 3 together and tiles 2 and 4 together because we need to use their respective overlap regions to mask cosmic rays where there is only a single image due to the dither pattern.

We separated the aligned images into separate directories by filter to make it easy to keep things organized.

adriz('id3b0[13]*flc.fits',output='v13',runfile='',context=False,in_memory=True,restore=False,preserve=False,skymethod='match',driz_sep_kernel='square',driz_sep_bits=2400,final_wht_type='IVM',final_pixfrac=0.8,final_bits=96)
adriz('id3b0[24]*flc.fits',output='v24',runfile='',context=False,in_memory=True,restore=False,preserve=False,skymethod='match',driz_sep_kernel='square',driz_sep_bits=2400,final_wht_type='IVM',final_pixfrac=0.8,final_bits=96)

We inspected the drizzled images to ensure that none of the gas clouds in the image show up with reduced wight in the weight map (which would indicate problems with the CR-rejection). The DQ masks in the in the individual input images should also be inspected to make sure only cosmic rays and bad pixels were masked.

Before we can proceed to drizzling the final mosaic we needed to take care of two more issues. For the images in visits 1 and 3, the right edges contain bad pixels. The images in visits 2 and 4 have bad pixels on their left side (see Figure 1). We masked those pixels by setting the DQ bits of the edges to 8.

imlist = glob.glob('id3b0[13]*flc.fits')

for im in imlist:
  hdu = fits.open(im,mode='update')
  hdu[3].data[:,:15]|=8
  hdu[6].data[:,:15]|=8
  hdu.close()

imlist = glob.glob('id3b0[24]*flc.fits')

for im in imlist:
  hdu = fits.open(im,mode='update')
  hdu[3].data[:,-15:]|=8
  hdu[6].data[:,-15:]|=8
  hdu.close()

Finally we drizzled the images together into a full mosaic. We drizzled the F658N filter first and used that product as the WCS reference image for the other two filters. Since the DQ masks have already been prepared, there is no need to run steps 1,3,4,5,6 of astrodrizzle. We only run step two to get the sky matched up in all images. One important parameter to change when running like this is resetbits. It should be set to zero to preserve the DQ masks we already made. Finally, remember that sky should be reset before drizzling images.

#reset sky here

adriz('i*flc.fits',output='f658n',runfile='f658n',context=False,resetbits=0,in_memory=True,restore=False,preserve=False,static=False,skysub=True,skymethod='match',driz_separate=False,median=False,blot=False,driz_cr=False,driz_combine=True,final_wht_type='IVM',final_pixfrac=0.8,final_bits=96,final_wcs=True,final_rot=0.)

adriz('i*flc.fits',output='f656n',runfile='f656n',context=False,resetbits=0,in_memory=True,restore=False,preserve=False,static=False,skysub=True,skymethod='match',driz_separate=False,median=False,blot=False,driz_cr=False,driz_combine=True,final_wht_type='IVM',final_pixfrac=0.8,final_bits=96,final_wcs=True,final_refimage='f658n_drc_sci.fits')

adriz('i*flc.fits',output='f502n',runfile='f502n',context=False,resetbits=0,in_memory=True,restore=False,preserve=False,static=False,skysub=True,skymethod='match',driz_separate=False,median=False,blot=False,driz_cr=False,driz_combine=True,final_wht_type='IVM',final_pixfrac=0.8,final_bits=96,final_wcs=True,final_refimage='f658n_drc_sci.fits')

In order to deliver these images as high level science products for MAST, they were renamed using the standard convention:

hlsp_heritage_hst_wfc3-bubble_nebula_fffff_v1_drc-ttt.fits

fffff - filter (f502n,f656n, or f658n)
ttt - the file type: “drc” (science-grade, drizzled images), or “wht” (weights)

Citation

The work described here is supported by the STScI Director’s Discretionary Funds (Program 14471, PI: Levay) and the Hubble Heritage project. If you utilize these data products for scientific purposes, please reference:

Avila, R.J., Levay, Z.G., Christian, C.A., Frattare, Green, J.D., M., Mack, J., Martlin, C., Meyett, S., Mutchler, M., & Noll, K.S., 2016, High-Level Science Products for the Mikulski Archive for Space Telescopes http://archive.stsci.edu/prepds/heritage/bubble/

References

[1]Suchkov, A. & Baggett, S. 2012 Instrument Science Report WFC3 2012-02
[2]http://pyregion.readthedocs.org
[3]http://www.astropy.org
[4]http://drizzlepac.stsci.edu