HST Source Identification and Photometry#

Photometry refers to measuring the amount of light that is emitted by a source (like a star, cluster, or galaxy) and detected by an instrument. The photometry is obtained by integrating the amount of flux detected within a given region (i.e. the aperture around the star), for a given filter (e.g. red, green, or blue). For our purposes, we convert this flux into a magnitude (I for red, V for green, B for blue) and can use these values to calculate the colors of each source (e.g. V-I, B-V, B-I), allowing us to conduct a deeper analysis of the source’s properties.

There are plenty of packages one can use to pull this data from an HST FITS file[1], but my preferred method is using the fleet of tools within the python package photutils. For my process, I set up a complete pipeline in the function PhotRun() in the AutoPhots.py script, but I’ll explain the steps for identifying HST point sources manually as well.

Note

While it is recommended to run AstroDrizzle through command line python, the scripts introduced here (and all others suggested in this guide) are fine to run within an iPython notebook. Just be sure to activate the proper environment (in my case, using conda activate stenv) before running jupyter notebook & in the command line. This will ensure your iPython notebook has access to all of the necessary python tools that were previously installed.

Using AutoPhots.RunPhots() for Everything#

Assuming you don’t mind black boxes, the quickest way to extract and correct the photometric data from HST is to simply run my RunPhots() function. This code will take care of all photometric and aperture correction steps for you, with some input from the user. The basic steps it takes are:

  • Find point sources with photutils.detection.DAOStarFinder;

  • Measure the photometry within apertures with radius ranging from 1 to 30 pixels with photutils.aperture.CircularAperture;

  • Calculate the apparent magnitudes of each object at each aperture radius;

  • Calculate an aperture correction from 3–20 pixels (by default) and 20–infinity by prompting user to identify ‘ideal’ stars; these ideal stars are also used to calculate aperture corrections from 10–20 (by default) and 20–infinity pixels for extended sources (i.e. clusters);

  • Apply aperture corrections to the apparent magnitudes and return the aperture correction factor and the correction error (both for point sources and extended sources as of version 1.5.0);

Running this code is fairly easy, but before you do, you will need to know the FWHM (full width at half maximum, the width of a Gaussian at half of its maximum height, as demonstrated in Fig. 8) of stars within the FITS file of interest. This can be measured within DS9[2]. Open your FITS file (be sure to set the scaling to something visible) and navigate to a relatively dark area with bright, isolated stars; you may have to set your cursor to pan using Edit > Pan first. Once in a good location, set your cursor to create a new region by selecting Edit > Region. Then under the Region menu located in the upper menu bar, go to Shape > Annulus. Click and drag somewhere on the image to create the annulus region. This region will be used to make a measurement of the radial profile of stars in this image, which will be used to estimate their FWHM.

../_images/fwhm.png

Fig. 8 Example of the FWHM of a Gaussian. Compare to Fig. 9, which plots only half of a Gaussian and, thus, gives the HWHM.#

To take a good radial profile of a star, you will need to update this region to include more than a single annulus. Double-click on the region to open up the Annulus properties window. You can add additional annuli by changing the inner and outer radius and increasing the annuli count. For me, I chose inner and outer radii of 1 and 31 pixels, and plotted 20 annuli. Click Generate followed by Apply to update your annulus region. You can save this region for later use under Region > Save. I recommend saving it using image coordinates, so that you can reuse the same region on different galaxies.

../_images/ds9_annuli.png

Fig. 9 Example of defining a region with several annuli, and the selection of Analysis > Radial Profile from the top menu.#

To measure the radial profile of a star, click and drag your region to center it on a bright, isolated star. Select the Annulus window (or double-click to bring it back up) and select Analysis > Radial Profile from the top menu bar (shown in Fig. 9). This will open a new window with the radial profile of the star (Fig. 10). Estimate the FWHM by eye. Do this for a few stars to get a good idea of a reasonable estimate. You will use this value whether you’re using RunPhots or doing your own source identification with DAOStarFinder in the next section.

../_images/radial_profile.png

Fig. 10 Example radial profile of an HST star. In this case, half-max occurs at around 0.15 arcseconds, so the FWHM of this star would be 0.3 arcseconds. Beware: you’ll want to ensure you’re looking at stars and not clusters, which will have a much broader FWHM and likely a higher peak surface brightness.#

You will also want to determine a good aperture radius with which to extract the photometry of compact star clusters, which will be read in to RunPhots() as extended_rad. The default is 10 pixels, which was sufficient for M81 but will likely be larger and smaller for your galaxy, depending on whether it is closer or farther than M81. For M101, I created regions around a few globular clusters and found that an aperture of 5 pixels is generally sufficient. An example of what a standard globular cluster looks like is given in Fig. 11.

../_images/M101_XRB_candidates_CXO011.png

Fig. 11 Example of a standard globular cluster in M101. Notice, the globular cluster here is large enough to fill the 1-\(\sigma\) radius of this XRB and is much larger than the 3 pixel aperture plotted surrounding its centroid. This demonstrates why it is necessary to set a separate aperture radius for extended sources like star clusters, compared to isolated stars (e.g. the other, smaller point sources visible in the image).#

To run RunPhots(), you will simply need to read in the FITS HDU, the galaxy name, the instrument (ACS/WFC or WFC3/UVIS), and the filter, though you pre-define additional parameters as well:

from XRBID.AutoPhots import RunPhots

# Running analysis on full mosaic. Can be done on individual
# fields using the 'suffix' parameter to differentiate savefile names
hdu = fits.open("M101_mosaic_acs_f555w_drc_sci.fits")

RunPhots(hdu, gal="M101", instrument="acs", filter="F555W", 
         fwhm_arcs=0.3, num_stars=25, reg_correction=[1,1], extended_rad=5)

Note

I choose to apply an additional pixel correction to the region files that result from RunPhots() by setting reg_correction = [1,1], which shifts all circular regions by 1 pixel in the x direction and 1 pixel in the y direction. This is because I noticed a small offset in the region files created from the coordinates of the point sources obtained by photutils aperture photometry. I don’t know what causes this disconnect, but since I intend to align the Chandra source coordinates to the HST region file coordinates, I use reg_correction to make sure the HST region file is properly aligned to the HST image.

This code may take a few minutes to run for each step, depending on the size of your FITS file. Then, it will prompt you to select ‘ideal’ stars for the aperture corrections by plotting the integrated radial profiles of randomly selected stars and requesting user approval.

The idea behind an aperture correction is to ensure that all of the light from a given star is captured and reflected in its measured flux/magnitude; since an aperture of infinite radius will detect the flux of an infinite number of sources other than the one you’re interested in, you need to select an aperture small enough to only measure the light from your selected star, but this aperture will undoubtedly ‘miss’ some of the light the star is giving off. An aperture correction is a means by which you can estimate and correct for the light that is presumably ‘cut off’ when you select an aperture of a given size. To do so, one should look at the radial profile of a given star and measure the flux/magnitude difference between the preferred aperture size (I use 3 pixels) and some larger aperture (e.g. 20 pixels). One then adds an additional correction factor measured from that larger aperture to infinity using the known Encircled Energy Fractions (EEF) for the instrument of choice[3]. Theoretically, this should estimate all of the light one expects to miss for an ideal star within a given HST observation, and this correction term can be applied to all remaining stars to get a better estimate of their total fluxes.

A good ‘ideal star’ is one with a magnitude that increases up until about 3 pixels, and then flattens off (see Fig. 12). RunPhots() will continue prompting the user for input until the number of ideal stars selected equals the input num_stars (the default is 20). As you add stars to the list of ideal stars, you will see their radial profiles plotted in grey, against which you can compare the radial profiles of the next randomly selected star. If you find that the same stars are being cycled through (as indicated by the star number in the title of the plot), this probably means there aren’t enough acceptable stars to meet the input criterion, and you should lower num_stars and try again. Once the criterion is met, RunPhots() will calculate and return the aperture correction and standard deviation. It may be a good idea to run the aperture correction a few times to make sure you’re minimizing the standard deviation, or you may not end up with an appropriate aperture correction. You can run just the aperture correction part of the code by calling AutoPhots.CorrectAp().

As of version 1.5.0, RunPhots() and CorrectAp() will also calculate the aperture correction for extended source given the aperture radius provided by the extended_rad parameter. By default, this value is 10 pixels, but one should select an aperture radius that best suits the compact clusters within the image of interest since farther galaxies will likely have clusters with smaller angular sizes. RunPhots() will then print *_extended.ecsv files from which the aperture photometry of clusters can be pulled.

../_images/aperture_example.png

Fig. 12 The radial profile of an `ideal’ star, showing the total flux (converted to magnitudes) within an aperture of a given radius. The integrated flux of stars in HST images will generally max out by 3 pixels and should be flat at increasing radius. If there are wiggles/spikes in the flux, this suggests the star is non well-isolated (light from a nearby star is interfering with the measurement), and that star should not be used for the aperture correction.#

Manual Source Identification and Photometry (w/o RunPhots())#

For those who prefer to run their own point source identification, whether because RunPhots() did not produce acceptable results or because you value the skill, you can extract sources using photutils instead, which should already be included in your python installation. The following instructions walk you through one means of manually identifying point sources in your HST images, extracting their photometry, and estimating an aperture correction for each image/filter, which you can use instead of RunPhots(). There almost certainly are other methods that you could use as well, but those will not be discussed here.

Identifying Point Sources with DAOStarFinder#

The main function used to find stars in a FITS file is the DAOStarFinder[4] function. This requires an estimate of the FWHM of stars on the image and some threshold amplitude above which a detection is found.

Open the FITS file in your imaging software of choice and use the analytics of that software to determine some reasonable measurement of the background noise in a dark area of the image, and the FWHM of a few average stars. For DS9, you can use the instructions in Using AutoPhots.RunPhots() for Everything to find the FWHM. An important thing to note is that DAOStarFinder requires the FWHM in pixels, but DS9 gives it in arcseconds. The pixel scale for is 0.05 arcsec per pixel for ACS/WFC and 0.03962 for WFC3/UVIS. This is usually stored under the FITS HDU header D001SCAL.

The background noise measurement is used to estimate a good threshold above which DAOStarFinder should search for stars. I use the standard deviation of the flux, which can be found easily in CARTA using the ‘Statistic Widget’ (the calculator button) on a selected region. This can also be obtained in python using sigma_clipped_stats from astropy.stats. I then use this value to define the threshold (by default, I use a threshold of 5 times the standard deviation):

from astropy.io import fits
from astropy.stats import sigma_clipped_stats
from photutils.detection import DAOStarFinder

fwhm = 0.3        # in arcseconds, from DS9
pixtoarcs = 0.05  # arcsec/pix, for ACS/WFC
data = fits.getdata('M101_mosaic_acs_f555w_drc_sci.fits')

# You can define some other sigma, depending on the quality of your data
dat_mean, dat_med, dat_std = sigma_clipped_stats(data, sigma=5)

# Pulling sources using DAOStarFind
daofind = DAOStarFind(fwhm=fwhm/pixtoarcs, threshold=5*dat_std)
objects = daofind(data)

DAOStarFind will return a table containing the coordinates of all identified sources, which can be used to make a region file that will plot in DS9 and CARTA (this can be done easily using my custom function WriteScript.WriteReg()). For reasons I don’t understand, the region file that comes from these coordinates often doesn’t align very well with the image itself, even though I believe the photometry that comes from these coordinates is accurate. When creating a region file, it may be a good idea to do a minor coordinate shift, just so that the regions align with the image and don’t cause confusion during the aperture correction step. Also, you’ll want to check the region file to make sure DAOStarFind isn’t missing any obvious sources. If it is, you’ll need to adjust your parameters (such as the FWHM) and run it again.

Extracting Photometry with aperture_photometry#

RunPhots() will conduct the aperture photometry for you with a default minimum radius of 3 pixels, but you can also run the aperture photometry yourself with photutils.aperture_photometry. The inputs for aperture_photometry are fairly simple: all you need is the FITS data (background subtracted) and a list of aperture radii at the positions of your sources of interest, built with photutils.aperture.CircularAperture(). Using the resulting objects table obtained from DAOStarFinder above:

from photutils.aperture import CircularAperture

# Pulling position of each DAOStarFind source
positions = np.transpose((objects['xcentroid'], objects['ycentroid']))

# Taking aperture photometry on a range of apertures from 1-30 pix
ap_rads = [i for i in range(1,31)]
apertures_full = [CircularAperture(positions, r=r) for r in ap_rads]

There are probably a couple of ways to generate a background subtracted image from the FITS data, but the way I prefer uses tools from photutils.background combined with SigmaClip from astropy.stats:

from photutils.background import Background2D, MedianBackground
from astropy.stats import SigmaClip

sigma_clip = SigmaClip(sigma=5)
bkg_estimator = MedianBackground()
bkg = Background2D(data, (50, 50), filter_size=(3, 3), 
                   sigma_clip=sigma_clip,
                   bkg_estimator=bkg_estimator)
data_sub = data - bkg.background

This background-subtracted data can then be used in the aperture photometry extraction (for cleaner photometry, you can also add an error calculation):

from photutils.aperture import aperture_photometry

phot_full = aperture_photometry(data_sub, apertures_full, method="center")

# or, alternatively, to include an error calculation
from photutils.utils import calc_total_error

hdu = fits.open('M101_mosaic_acs_f555w_drc_sci.fits')
phot_full = aperture_photometry(data_sub, apertures_full, 
    		            error=calc_total_error(data, data-data_sub,
    				  effective_gain=hdu[0].header["EXPTIME"]))

phot_full.write("<filename>.ecsv")

The resulting .ecsv file will contain the coordinates of each source and the integrated flux within each aperture radius (in this case, 1–30 pixels). For normal stars, I generally use the flux within a 3-pixel aperture to represent a single star, as this radius is usually large enough to collect most of the stellar light but small enough for the flux not to be influenced by contamination from a neighboring star. However, any defined aperture is sure to miss some of the light of the chosen star, which is why an aperture correction is also needed to fully represent the stellar flux of a star of interest.

Estimating Aperture Corrections#

RunPhots() will automatically conduct the aperture corrections using a second custom function, CorrectAp(). The philosophy behind aperture corrections is described in detailed above in Using AutoPhots.RunPhots() for Everything or, in a more official capacity, here: https://www.stsci.edu/hst/instrumentation/acs/data-analysis/aperture-corrections

To perform a manual aperture correction, you will want to select a sufficient number of ‘ideal’ isolated stars and find the magnitude difference between the 3 pixel and 20 pixel aperture photometry for each star[5]. Plot their radial profiles to check that it looks similar to the ideal case represented by Fig. 12. The median of these difference values (or some other well-argued statistical measure) is the correction term you will apply to the 3-pixel photometry of all other stars of interest. An additional term representing the magnitude difference between the 20 pixel radius and infinity should also be applied; this value can be found in the aperture correction link above for ACS/WFC, or here for WFC3/UVIS: https://www.stsci.edu/hst/instrumentation/wfc3/data-analysis/photometric-calibration/uvis-encircled-energy

This EEF value is given as the fraction of the light encircled by the maximum aperture, which should be used to calculate how much more light needs to be added to capture 100% of the stellar emissions (that is, out to infinity).

Be sure to save these values for each filter, as well as their standard deviations. For my data, I obtained the following values:

ap555_acs = -0.711
ap555err_acs = 0.220
ap435_acs = -0.660
ap435err_acs = 0.248
ap814_acs = -0.561
ap814err_acs = 0.253

The values are negative because they are to be added to the magnitudes from the 3-pixel aperture photometry representing a given star. More negative magnitudes indicate brighter stars, and the aperture correction should make the star appear brighter as we add back the missing light.