MIRI PSF Photometry with Photutils#
Author: Ori Fox
Submitted: November, 2023
Updated: November, 2023
Use case: PSF Photometry using Photutils. The purpose here is to illustrate the workflow and runtime for using Photutils in a variety of use cases.
Generally, PSF photometry for data from a space telescope is most accurately performed on pre-mosaiced data. The mosaic process changes the inherent PSF, blurring it both due to resampling and mixing PSFs at different detector positions and rotations. Additionally, accurate theoretical PSF models (e.g., from STPSF) are not available for mosaiced data. While an empirical PSF could be constructed (e.g., using Photutils ePSFBuilder) for mosaiced data, the results will generally not be as accurate as performing PSF photometry on the pre-mosaiced data.
NOTE: A companion notebook exists that illustrates how to use perform PSF photometry on both Level 2 and Level 3 data using a new software program called space_phot.
Data: MIRI Data PID 1028 (Calibration Program; Single Star Visit 006 A5V dwarf 2MASSJ17430448+6655015) and MIRI Data PID 1171 (LMC; Multiple Stars).
Tools: photutils, stpsf, jwst
Cross-Instrument: MIRI
Documentation: This notebook is part of a STScI’s larger post-pipeline Data Analysis Tools Ecosystem and can be downloaded directly from the JDAT Notebook Github directory.
Table of contents#
Introduction
1.1 Python Imports
1.2 Set up STPSF and SynphotDownload JWST MIRI Data
Single Bright Object
3.1 Single Level 2 File
3.2 Generate empirical PSF grid for MIRI F770W using STPSF
3.3 PSF PhotometryFaint/Upper Limit, Single Object
4.1 Multiple, Level2 FilesStellar Field (LMC)
5.1 Multiple Stars, Single Level 2 File
5.2 Generate empirical PSF grid for MIRI F560W using STPSF
5.3 PSF Photometry
1. Introduction #
GOALS:
Perform PSF photometry on JWST MIRI images with the Photutils PSF Photometry tools using a grid of empirical PSF models from STPSF.
The notebook shows how to:
generate a grid of empirical PSF models from STPSF
perform PSF photometry on the image using the PSFPhotometry class
Data:
MIRI Data PID 1028 (Calibration Program), F770W
MIRI Data PID 1171 (LMC), F560W/F770W
1.1 Python Imports #
import glob
import os
import shutil
import tarfile
from pandas import DataFrame
import matplotlib.pyplot as plt
import numpy as np
import stpsf
from urllib.parse import urlparse
import requests
import astropy.units as u
from astropy.coordinates import SkyCoord
from astropy.io import fits
from astropy.nddata import extract_array
from astropy.table import Table
from astropy.visualization import simple_norm
from astroquery.mast import Observations
from jwst.datamodels import ImageModel
from photutils.aperture import CircularAperture
from photutils.background import LocalBackground, MADStdBackgroundRMS, MMMBackground
from photutils.detection import DAOStarFinder
from photutils.psf import GriddedPSFModel, PSFPhotometry
1.2 Download and Set up Required Data for STPSF and Synphot #
# Set environmental variables
os.environ["STPSF_PATH"] = "./stpsf-data/stpsf-data"
os.environ["PYSYN_CDBS"] = "./grp/redcat/trds/"
# required stpsf data
boxlink = 'https://stsci.box.com/shared/static/kqfolg2bfzqc4mjkgmujo06d3iaymahv.gz'
boxfile = './stpsf-data-LATEST.tar.gz'
synphot_url = 'http://ssb.stsci.edu/trds/tarfiles/synphot5.tar.gz'
synphot_file = './synphot5.tar.gz'
stpsf_folder = './stpsf-data'
synphot_folder = './grp'
def download_file(url, dest_path, timeout=60):
parsed_url = urlparse(url)
if parsed_url.scheme not in ["http", "https"]:
raise ValueError(f"Unsupported URL scheme: {parsed_url.scheme}")
response = requests.get(url, stream=True, timeout=timeout)
response.raise_for_status()
with open(dest_path, "wb") as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
# Gather stpsf files
psfExist = os.path.exists(stpsf_folder)
if not psfExist:
os.makedirs(stpsf_folder)
download_file(boxlink, boxfile)
gzf = tarfile.open(boxfile)
gzf.extractall(stpsf_folder, filter='data')
# Gather synphot files
synExist = os.path.exists(synphot_folder)
if not synExist:
os.makedirs(synphot_folder)
download_file(synphot_url, synphot_file)
gzf = tarfile.open(synphot_file)
gzf.extractall('./', filter='data')
2. Download JWST MIRI Data #
# Download Proposal ID 1028 F770W data
# Define source and destination directories
source_dir = 'mastDownload/JWST/'
destination_dir = 'mast/01028/'
if os.path.isdir(destination_dir):
print(f'Data already downloaded to {os.path.abspath(destination_dir)}')
else:
# Query the MAST (Mikulski Archive for Space Telescopes) database for observations
# with proposal ID 1028 and the F770W filter
obs = Observations.query_criteria(proposal_id=1028, filters=['F770W'])
# Get a list of products associated with the located observation
plist = Observations.get_product_list(obs)
# Filter the product list to include only specific product subgroups
fplist = Observations.filter_products(plist, productSubGroupDescription=['CAL', 'I2D', 'ASN'])
# Download the selected products from the MAST database
Observations.download_products(fplist)
# Create the destination directory
os.makedirs(destination_dir)
# Use glob to find all files matching the pattern
files_to_copy = glob.glob(os.path.join(source_dir, 'j*/jw01028*'))
# Copy the matching files to the destination directory
for file_path in files_to_copy:
shutil.copy(file_path, destination_dir)
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_20250617t142750_image2_00013_asn.json to ./mastDownload/JWST/jw01028006001_02101_00004_mirimage/jw01028-o006_20250617t142750_image2_00013_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_20250617t142750_image2_00014_asn.json to ./mastDownload/JWST/jw01028006001_02101_00003_mirimage/jw01028-o006_20250617t142750_image2_00014_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_20250617t142750_image2_00015_asn.json to ./mastDownload/JWST/jw01028006001_02101_00002_mirimage/jw01028-o006_20250617t142750_image2_00015_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_20250617t142750_image2_00016_asn.json to ./mastDownload/JWST/jw01028006001_02101_00001_mirimage/jw01028-o006_20250617t142750_image2_00016_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_20250617t142750_image3_00004_asn.json to ./mastDownload/JWST/jw01028-o006_t001_miri_f770w/jw01028-o006_20250617t142750_image3_00004_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028-o006_t001_miri_f770w_i2d.fits to ./mastDownload/JWST/jw01028-o006_t001_miri_f770w/jw01028-o006_t001_miri_f770w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01028006001_02101_00001_mirimage/jw01028006001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01028006001_02101_00001_mirimage/jw01028006001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01028006001_02101_00002_mirimage/jw01028006001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01028006001_02101_00002_mirimage/jw01028006001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01028006001_02101_00003_mirimage/jw01028006001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01028006001_02101_00003_mirimage/jw01028006001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01028006001_02101_00004_mirimage/jw01028006001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01028006001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01028006001_02101_00004_mirimage/jw01028006001_02101_00004_mirimage_i2d.fits ...
[Done]
# Download Proposal ID 1171 F550W and F770W data
# Define source and destination directories
source_dir = 'mastDownload/JWST/'
destination_dir = 'mast/01171/'
if os.path.isdir(destination_dir):
print(f'Data already downloaded to {os.path.abspath(destination_dir)}')
else:
# Query the MAST (Mikulski Archive for Space Telescopes) database for observations
# with proposal ID 1171 and the F550W and F770W filters
obs = Observations.query_criteria(proposal_id=1171, filters=['F560W', 'F770W'])
# Get a list of products associated with the located observation
plist = Observations.get_product_list(obs)
# Filter the product list to include only specific product subgroups
fplist = Observations.filter_products(plist, productSubGroupDescription=['CAL', 'I2D', 'ASN'])
# Download the selected products from the MAST database
Observations.download_products(fplist)
# Create the destination directory
os.makedirs(destination_dir)
# Use glob to find all files matching the pattern
files_to_copy = glob.glob(os.path.join(source_dir, 'j*/jw01171*'))
# Copy the matching files to the destination directory
for file_path in files_to_copy:
shutil.copy(file_path, destination_dir)
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_20231102t191130_image2_00005_asn.json to ./mastDownload/JWST/jw01171001001_02101_00004_mirimage/jw01171-o001_20231102t191130_image2_00005_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_20231102t191130_image2_00006_asn.json to ./mastDownload/JWST/jw01171001001_02101_00003_mirimage/jw01171-o001_20231102t191130_image2_00006_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_20231102t191130_image2_00007_asn.json to ./mastDownload/JWST/jw01171001001_02101_00002_mirimage/jw01171-o001_20231102t191130_image2_00007_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_20231102t191130_image2_00008_asn.json to ./mastDownload/JWST/jw01171001001_02101_00001_mirimage/jw01171-o001_20231102t191130_image2_00008_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_20231102t191130_image3_00002_asn.json to ./mastDownload/JWST/jw01171-o001_t001_miri_f770w/jw01171-o001_20231102t191130_image3_00002_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o001_t001_miri_f770w_i2d.fits to ./mastDownload/JWST/jw01171-o001_t001_miri_f770w/jw01171-o001_t001_miri_f770w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_20231102t191130_image2_00005_asn.json to ./mastDownload/JWST/jw01171002001_02101_00004_mirimage/jw01171-o002_20231102t191130_image2_00005_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_20231102t191130_image2_00006_asn.json to ./mastDownload/JWST/jw01171002001_02101_00003_mirimage/jw01171-o002_20231102t191130_image2_00006_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_20231102t191130_image2_00007_asn.json to ./mastDownload/JWST/jw01171002001_02101_00002_mirimage/jw01171-o002_20231102t191130_image2_00007_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_20231102t191130_image2_00008_asn.json to ./mastDownload/JWST/jw01171002001_02101_00001_mirimage/jw01171-o002_20231102t191130_image2_00008_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_20231102t191130_image3_00002_asn.json to ./mastDownload/JWST/jw01171-o002_t001_miri_f770w/jw01171-o002_20231102t191130_image3_00002_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o002_t001_miri_f770w_i2d.fits to ./mastDownload/JWST/jw01171-o002_t001_miri_f770w/jw01171-o002_t001_miri_f770w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_20231102t191130_image2_00005_asn.json to ./mastDownload/JWST/jw01171003001_02101_00004_mirimage/jw01171-o003_20231102t191130_image2_00005_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_20231102t191130_image2_00006_asn.json to ./mastDownload/JWST/jw01171003001_02101_00003_mirimage/jw01171-o003_20231102t191130_image2_00006_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_20231102t191130_image2_00007_asn.json to ./mastDownload/JWST/jw01171003001_02101_00002_mirimage/jw01171-o003_20231102t191130_image2_00007_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_20231102t191130_image2_00008_asn.json to ./mastDownload/JWST/jw01171003001_02101_00001_mirimage/jw01171-o003_20231102t191130_image2_00008_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_20231102t191130_image3_00002_asn.json to ./mastDownload/JWST/jw01171-o003_t001_miri_f770w/jw01171-o003_20231102t191130_image3_00002_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o003_t001_miri_f770w_i2d.fits to ./mastDownload/JWST/jw01171-o003_t001_miri_f770w/jw01171-o003_t001_miri_f770w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_20231102t191130_image2_00005_asn.json to ./mastDownload/JWST/jw01171004001_02101_00004_mirimage/jw01171-o004_20231102t191130_image2_00005_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_20231102t191130_image2_00006_asn.json to ./mastDownload/JWST/jw01171004001_02101_00003_mirimage/jw01171-o004_20231102t191130_image2_00006_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_20231102t191130_image2_00007_asn.json to ./mastDownload/JWST/jw01171004001_02101_00002_mirimage/jw01171-o004_20231102t191130_image2_00007_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_20231102t191130_image2_00008_asn.json to ./mastDownload/JWST/jw01171004001_02101_00001_mirimage/jw01171-o004_20231102t191130_image2_00008_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_20231102t191130_image3_00002_asn.json to ./mastDownload/JWST/jw01171-o004_t001_miri_f560w/jw01171-o004_20231102t191130_image3_00002_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o004_t001_miri_f560w_i2d.fits to ./mastDownload/JWST/jw01171-o004_t001_miri_f560w/jw01171-o004_t001_miri_f560w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_20231102t191130_image2_00005_asn.json to ./mastDownload/JWST/jw01171005001_02101_00004_mirimage/jw01171-o005_20231102t191130_image2_00005_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_20231102t191130_image2_00006_asn.json to ./mastDownload/JWST/jw01171005001_02101_00003_mirimage/jw01171-o005_20231102t191130_image2_00006_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_20231102t191130_image2_00007_asn.json to ./mastDownload/JWST/jw01171005001_02101_00002_mirimage/jw01171-o005_20231102t191130_image2_00007_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_20231102t191130_image2_00008_asn.json to ./mastDownload/JWST/jw01171005001_02101_00001_mirimage/jw01171-o005_20231102t191130_image2_00008_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_20231102t191130_image3_00002_asn.json to ./mastDownload/JWST/jw01171-o005_t001_miri_f770w/jw01171-o005_20231102t191130_image3_00002_asn.json ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171-o005_t001_miri_f770w_i2d.fits to ./mastDownload/JWST/jw01171-o005_t001_miri_f770w/jw01171-o005_t001_miri_f770w_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01171001001_02101_00001_mirimage/jw01171001001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01171001001_02101_00001_mirimage/jw01171001001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01171001001_02101_00002_mirimage/jw01171001001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01171001001_02101_00002_mirimage/jw01171001001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01171001001_02101_00003_mirimage/jw01171001001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01171001001_02101_00003_mirimage/jw01171001001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01171001001_02101_00004_mirimage/jw01171001001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171001001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01171001001_02101_00004_mirimage/jw01171001001_02101_00004_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01171002001_02101_00001_mirimage/jw01171002001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01171002001_02101_00001_mirimage/jw01171002001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01171002001_02101_00002_mirimage/jw01171002001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01171002001_02101_00002_mirimage/jw01171002001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01171002001_02101_00003_mirimage/jw01171002001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01171002001_02101_00003_mirimage/jw01171002001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01171002001_02101_00004_mirimage/jw01171002001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171002001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01171002001_02101_00004_mirimage/jw01171002001_02101_00004_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01171003001_02101_00001_mirimage/jw01171003001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01171003001_02101_00001_mirimage/jw01171003001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01171003001_02101_00002_mirimage/jw01171003001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01171003001_02101_00002_mirimage/jw01171003001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01171003001_02101_00003_mirimage/jw01171003001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01171003001_02101_00003_mirimage/jw01171003001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01171003001_02101_00004_mirimage/jw01171003001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171003001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01171003001_02101_00004_mirimage/jw01171003001_02101_00004_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01171004001_02101_00001_mirimage/jw01171004001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01171004001_02101_00001_mirimage/jw01171004001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01171004001_02101_00002_mirimage/jw01171004001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01171004001_02101_00002_mirimage/jw01171004001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01171004001_02101_00003_mirimage/jw01171004001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01171004001_02101_00003_mirimage/jw01171004001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01171004001_02101_00004_mirimage/jw01171004001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171004001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01171004001_02101_00004_mirimage/jw01171004001_02101_00004_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00001_mirimage_cal.fits to ./mastDownload/JWST/jw01171005001_02101_00001_mirimage/jw01171005001_02101_00001_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00001_mirimage_i2d.fits to ./mastDownload/JWST/jw01171005001_02101_00001_mirimage/jw01171005001_02101_00001_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00002_mirimage_cal.fits to ./mastDownload/JWST/jw01171005001_02101_00002_mirimage/jw01171005001_02101_00002_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00002_mirimage_i2d.fits to ./mastDownload/JWST/jw01171005001_02101_00002_mirimage/jw01171005001_02101_00002_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00003_mirimage_cal.fits to ./mastDownload/JWST/jw01171005001_02101_00003_mirimage/jw01171005001_02101_00003_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00003_mirimage_i2d.fits to ./mastDownload/JWST/jw01171005001_02101_00003_mirimage/jw01171005001_02101_00003_mirimage_i2d.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00004_mirimage_cal.fits to ./mastDownload/JWST/jw01171005001_02101_00004_mirimage/jw01171005001_02101_00004_mirimage_cal.fits ...
[Done]
Downloading URL https://mast.stsci.edu/api/v0.1/Download/file?uri=mast:JWST/product/jw01171005001_02101_00004_mirimage_i2d.fits to ./mastDownload/JWST/jw01171005001_02101_00004_mirimage/jw01171005001_02101_00004_mirimage_i2d.fits ...
[Done]
3. Single Bright Star #
The purpose of this section is to illustrate how to perform PSF photometry on a single bright star. While aperture photometry is feasible in isolated cases, the user may find PSF photometry preferable in crowded fields or complicated backgrounds.
3.1 Single Level 2 File #
In this example, we fit a single, bright source in a single Level 2 images. For a collection of Level 2 images, we could fit each Level 2 image individually and then average the measured fluxes.
Useful references:
HST Documentation on PSF Photometry: https://www.stsci.edu/hst/instrumentation/wfc3/data-analysis/psf
WFPC2 Stellar Photometry with HSTPHOT: https://ui.adsabs.harvard.edu/abs/2000PASP..112.1383D/abstract
Photutils PSF Fitting Photometry: https://photutils.readthedocs.io/en/stable/user_guide/psf.html
# get the level 2 filenames
path = "./mast/01028/"
level2 = sorted(glob.glob(os.path.join(path, '*cal.fits')))
level2
['./mast/01028/jw01028006001_02101_00001_mirimage_cal.fits',
'./mast/01028/jw01028006001_02101_00002_mirimage_cal.fits',
'./mast/01028/jw01028006001_02101_00003_mirimage_cal.fits',
'./mast/01028/jw01028006001_02101_00004_mirimage_cal.fits']
# display the first level-2 image
data = fits.getdata(level2[0])
norm = simple_norm(data, 'sqrt', percent=99)
fig, ax = plt.subplots(figsize=(20, 12))
im = ax.imshow(data, origin='lower', norm=norm, cmap='gray')
clb = plt.colorbar(im, label='MJy/sr')
ax.set_xlabel('Pixels')
ax.set_ylabel('Pixels')
plt.show()

# Change all DQ flagged pixels to NaN.
# Here, we'll overwrite the original CAL file.
# Reference for JWST DQ Flag Definitions: https://jwst-pipeline.readthedocs.io/en/latest/jwst/references_general/references_general.html
# In this case, we choose all DQ > 10, but users are encouraged to choose their own values accordingly.
filename = level2[0]
with ImageModel(filename) as model:
model.data[model.dq >= 10] = np.nan
model.save(filename)
# Re-display the image
data = fits.getdata(level2[0])
norm = simple_norm(data, 'sqrt', percent=99)
fig, ax = plt.subplots(figsize=(20, 12))
im = ax.imshow(data, origin='lower', norm=norm, cmap='gray')
clb = plt.colorbar(im, label='MJy/sr')
ax.set_xlabel('Pixels')
ax.set_ylabel('Pixels')
plt.show()

# Zoom in to see the source. In this case, our source is from MIRI Program ID #1028, a Calibration Program.
# We are using Visit 006, which targets the A5V dwarf 2MASSJ17430448+6655015
# Reference Link: http://simbad.cds.unistra.fr/simbad/sim-basic?Ident=2MASSJ17430448%2B6655015&submit=SIMBAD+search
source_location = SkyCoord('17:43:04.4879', '+66:55:01.837', unit=(u.hourangle, u.deg))
with ImageModel(filename) as model:
x, y = model.meta.wcs.world_to_pixel(source_location)
cutout = extract_array(data, (21, 21), (y, x))
fig, ax = plt.subplots(figsize=(8, 8))
norm2 = simple_norm(cutout, 'log', percent=99)
im = ax.imshow(cutout, origin='lower', norm=norm2, cmap='gray')
clb = plt.colorbar(im, label='MJy/sr', shrink=0.8)
ax.set_title('PID1028, Obs006')
ax.set_xlabel('Pixels')
ax.set_ylabel('Pixels')
plt.show()

3.2 Generate empirical PSF grid for MIRI F770W using STPSF #
Let’s now use STPSF to generate an empirical grid of ePSF models for MIRI F770W.
The output will be a Photutils GriddedPSFModel containing a 2x2 grid of detector-position-dependent empirical PSFs, each oversampled by a factor of 4. Note that we save the PSF grid to a FITS file (via save=True
) called miri_mirim_f770w_fovp101_samp4_npsf4.fits
. To save time in future runs, we load this FITS file directly into a GriddedPSFModel
object:
psfgrid_filename = 'miri_mirim_f770w_fovp101_samp4_npsf4.fits'
if not os.path.exists(psfgrid_filename):
miri = stpsf.MIRI()
miri.filter = 'F770W'
miri.detector = 'MIRIM'
psf_model = miri.psf_grid(num_psfs=4, all_detectors=False, verbose=True, save=True)
else:
psf_model = GriddedPSFModel.read(psfgrid_filename)
psf_model
Running instrument: MIRI, filter: F770W
Running detector: MIRIM
Position 1/4: (0, 0) pixels
Position 1/4 centroid: (np.float64(201.4023624749013), np.float64(201.47046390597333))
Position 2/4: (0, 1023) pixels
Position 2/4 centroid: (np.float64(201.30690755776234), np.float64(201.3328394993336))
Position 3/4: (1023, 0) pixels
Position 3/4 centroid: (np.float64(201.46001999611337), np.float64(201.57406698621335))
Position 4/4: (1023, 1023) pixels
Position 4/4 centroid: (np.float64(201.71435554877664), np.float64(201.48197003471248))
Saving file: miri_mirim_f770w_fovp101_samp4_npsf4.fits
<GriddedPSFModel(flux=1., x_0=0., y_0=0.)>
# display the PSF grid
psf_model.plot_grid()


# display the PSF grid deltas from the mean ePSF
psf_model.plot_grid(deltas=True)


3.3 PSF Photometry #
Now let’s use our gridded PSF model to perform PSF photometry.
# load data and convert units from MJy/sr to uJy
with ImageModel(filename) as model:
unit = u.Unit(model.meta.bunit_data)
data = model.data << unit
error = model.err << unit
# use pixel area map because of geometric distortion in level-2 data
pixel_area = model.area * model.meta.photometry.pixelarea_steradians * u.sr
data *= pixel_area
error *= pixel_area
data = data.to(u.uJy)
error = error.to(u.uJy)
data.unit, error.unit
(Unit("uJy"), Unit("uJy"))
To perform photometry on a single source we can input a Table containing its (x, y) position.
init_params = Table()
init_params['x'] = [x]
init_params['y'] = [y]
init_params
x | y |
---|---|
float64 | float64 |
691.0126389413533 | 512.5838903334229 |
# we turn off the finder because we input the source position
fit_shape = 5
localbkg_estimator = LocalBackground(5, 10, bkg_estimator=MMMBackground())
psfphot = PSFPhotometry(psf_model, fit_shape, finder=None, aperture_radius=fit_shape,
localbkg_estimator=localbkg_estimator, progress_bar=True)
phot = psfphot(data, error=error, init_params=init_params)
phot
id | group_id | group_size | local_bkg | x_init | y_init | flux_init | x_fit | y_fit | flux_fit | x_err | y_err | flux_err | npixfit | qfit | cfit | flags |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
uJy | uJy | uJy | uJy | |||||||||||||
int64 | int64 | int64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | int64 | float64 | float64 | int64 |
1 | 1 | 1 | 1.4397251162293783 | 691.0126389413533 | 512.5838903334229 | 475.7955370966203 | 691.1798603021881 | 512.9107570382915 | 465.11685232449025 | 0.0010116489713053985 | 0.001024766468371471 | 0.5138472957774761 | 25 | 0.7057654379338035 | -0.017056128265791032 | 0 |
# convert fit flux from uJy to ABmag
flux = phot['flux_fit']
flux_err = phot['flux_err']
mag = phot['flux_fit'].to(u.ABmag)
magerr = 2.5 * np.log10(1.0 + (flux_err / flux))
magerr = magerr.value * u.ABmag
mag, magerr
(<Magnitude [17.23109481] mag(AB)>, <Magnitude [0.00119883] mag(AB)>)
fig, ax = plt.subplots(ncols=3, figsize=(12, 4))
shape = (21, 21)
cutout1 = extract_array(data.value, shape, (y, x))
norm = simple_norm(cutout1, 'log', percent=98)
im1 = ax[0].imshow(cutout1, origin='lower', norm=norm)
ax[0].set_title(r'Data ($\mu$Jy)')
plt.colorbar(im1, shrink=0.7)
model = psfphot.make_model_image(data.shape, psf_shape=shape)
cutout2 = extract_array(model, shape, (y, x))
im2 = ax[1].imshow(cutout2, origin='lower', norm=norm)
ax[1].set_title('Fit PSF Model')
plt.colorbar(im2, shrink=0.7)
resid = psfphot.make_residual_image(data, psf_shape=shape)
cutout3 = extract_array(resid, shape, (y, x))
norm3 = simple_norm(cutout3.value, 'sqrt', percent=99)
im3 = ax[2].imshow(cutout3.value, origin='lower', norm=norm3)
ax[2].set_title('Residual')
plt.colorbar(im3, shrink=0.7)
plt.show()

4. Faint/Upper Limit, Single Object #
The purpose of this section is to illustrate how to calculate an upper limit at a fixed (x, y) position using forced PSF photometry a blank part of the sky.
We’ll use the same data as Section 3.
# load data and convert units from MJy/sr to uJy
with ImageModel(filename) as model:
unit = u.Unit(model.meta.bunit_data)
data = model.data << unit
error = model.err << unit
pixel_area = pixel_area = model.meta.photometry.pixelarea_steradians * u.sr
data *= pixel_area
error *= pixel_area
data = data.to(u.uJy)
error = error.to(u.uJy)
source_location = SkyCoord('17:43:00.0332', '+66:54:42.677', unit=(u.hourangle, u.deg))
with ImageModel(filename) as model:
x, y = model.meta.wcs.world_to_pixel(source_location)
cutout = extract_array(data.value, (21, 21), (y, x))
fig, ax = plt.subplots()
norm = simple_norm(cutout, 'sqrt', percent=95)
im = ax.imshow(cutout, origin='lower', norm=norm, cmap='gray')
clb = plt.colorbar(im, label=r'$\mu$Jy')
ax.set_title('PID1028, Obs006')
ax.set_xlabel('Pixels')
ax.set_ylabel('Pixels')
plt.show()

# to perform forced photometry, we set the (x, y) source position
# AND we fix the PSF model position so that it does not vary in the fit
# (only flux will be fit)
init_params = Table()
init_params['x'] = [x]
init_params['y'] = [y]
# This requires photutils 1.11.0
psf_model_forced = psf_model.copy()
psf_model_forced.x_0.fixed = True
psf_model_forced.y_0.fixed = True
psf_model_forced.fixed
{'flux': False, 'x_0': True, 'y_0': True}
fit_shape = 5
localbkg_estimator = LocalBackground(5, 10, bkg_estimator=MMMBackground())
psfphot = PSFPhotometry(psf_model_forced, fit_shape, finder=None, aperture_radius=fit_shape,
localbkg_estimator=localbkg_estimator, progress_bar=True)
phot = psfphot(data, error=error, init_params=init_params)
phot
id | group_id | group_size | local_bkg | x_init | y_init | flux_init | x_fit | y_fit | flux_fit | x_err | y_err | flux_err | npixfit | qfit | cfit | flags |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
uJy | uJy | uJy | uJy | |||||||||||||
int64 | int64 | int64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | int64 | float64 | float64 | int64 |
1 | 1 | 1 | 1.2926821657735057 | 559.0832487866767 | 772.8615809731978 | 99.69285815735192 | 559.0832487866767 | 772.8615809731978 | -0.38089014331448917 | nan | nan | 0.06349041646685509 | 25 | -93.32672605807173 | 0.4099578318266419 | 4 |
# To calculate upper limit, multiply the flux_err by your desired sigma
sigma = 3.0
limit = sigma * phot['flux_err']
limit.to(u.ABmag)
Note: you can go significantly deeper with the Level 3 combined data product#
5. Stellar Field (LMC) #
In this case, we are going to do the same steps as in Section 3, but for multiple stars. The purpose is to illustrate the workflow and runtime for using Photutils on a large number of stars.
5.1 Multiple Stars, Single Level 2 File #
# Find stars in Level 3 File
path = './mast/01171/'
level3 = os.path.join(path, 'jw01171-o004_t001_miri_f560w_i2d.fits')
level3
'./mast/01171/jw01171-o004_t001_miri_f560w_i2d.fits'
# Get rough estimate of background (there are better ways to do background subtraction)
bkgrms = MADStdBackgroundRMS()
mmm_bkg = MMMBackground()
with ImageModel(level3) as model:
wcs_l3 = model.meta.wcs
std = bkgrms(model.data)
bkg = mmm_bkg(model.data)
data_bkgsub = model.data.copy()
data_bkgsub -= bkg
# Find stars
# F560W FWHM = 1.882 pix
fwhm_psf = 1.882
threshold = 5.0
daofind = DAOStarFinder(threshold=threshold * std, fwhm=fwhm_psf, exclude_border=True, min_separation=10)
found_stars = daofind(data_bkgsub)
found_stars.pprint_all(max_lines=10)
id xcentroid ycentroid sharpness roundness1 roundness2 npix peak flux mag daofind_mag
--- ------------------ ------------------ ------------------ ----------- -------------------- ---- ----------- ---------- --- ---------------------
1 546.2615248590856 5.400907067001771 0.7041937380599614 0.46773428 0.04273256330788263 25 -0.8653275 -50.092262 nan -0.5413295965257243
2 789.0983970730795 6.312157835017224 0.6691237944354219 -0.17942303 -0.8079555096758687 25 -0.57612133 -34.95916 nan -0.1035249124958943
3 845.9799634503643 3.675797141070524 0.6829976607805458 0.043498766 -0.42254093349077243 25 -1.1719772 -46.178497 nan -0.179222451244508
... ... ... ... ... ... ... ... ... ... ...
788 1005.1187213604594 1062.3368573824348 0.6862059219157299 -0.44935676 -0.8216906677208756 25 -0.69887817 -38.484135 nan -0.037972898002874234
789 399.3766175963356 1064.9409739772366 0.3060837128458461 -0.1559235 -0.21203561885367186 25 -0.74871683 -34.341244 nan -0.024118448038772944
790 566.9700693080139 1065.048267845045 0.5650444893283237 -0.37038124 -0.5505482861764636 25 0.51578784 -21.200844 nan -0.5359357398718912
Length = 790 rows
# plot the found stars
norm = simple_norm(data_bkgsub, 'sqrt', percent=99)
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(data_bkgsub, origin='lower', norm=norm)
xypos = zip(found_stars['xcentroid'], found_stars['ycentroid'])
aper = CircularAperture(xypos, r=10)
aper.plot(ax, color='red')
plt.show()

fig, ax = plt.subplots(nrows=2, figsize=(10, 8))
ax[0].scatter(found_stars['mag'], found_stars['sharpness'], s=10, color='k')
ax[0].set_xlabel('mag')
ax[0].set_ylabel('sharpness')
ax[1].scatter(found_stars['mag'], found_stars['roundness2'], s=10, color='k')
ax[1].set_xlabel('mag')
ax[1].set_ylabel('roundness')
mag0 = -3.0
mag1 = -5.0
for ax_ in ax:
ax_.axvline(mag0, color='red', linestyle='dashed')
ax_.axvline(mag1, color='red', linestyle='dashed')
sh0 = 0.40
sh1 = 0.82
ax[0].axhline(sh0, color='red', linestyle='dashed')
ax[0].axhline(sh1, color='red', linestyle='dashed')
rnd0 = -0.40
rnd1 = 0.40
ax[1].axhline(rnd0, color='red', linestyle='dashed')
ax[1].axhline(rnd1, color='red', linestyle='dashed')
plt.show()

mask = ((found_stars['mag'] < mag0) & (found_stars['mag'] > mag1) & (found_stars['roundness2'] > rnd0)
& (found_stars['roundness2'] < rnd1) & (found_stars['sharpness'] > sh0)
& (found_stars['sharpness'] < sh1) & (found_stars['xcentroid'] > 100) & (found_stars['xcentroid'] < 700)
& (found_stars['ycentroid'] > 100) & (found_stars['ycentroid'] < 700))
found_stars_sel = found_stars[mask]
print('Number of stars found originally:', len(found_stars))
print('Number of stars in final selection:', len(found_stars_sel))
Number of stars found originally: 790
Number of stars in final selection: 63
# plot the selected stars
norm = simple_norm(data_bkgsub, 'sqrt', percent=99)
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(data_bkgsub, origin='lower', norm=norm)
xypos = zip(found_stars_sel['xcentroid'], found_stars_sel['ycentroid'])
aper = CircularAperture(xypos, r=10)
aper.plot(ax, color='red')
plt.show()

5.2 Generate empirical PSF grid for MIRI F560W using STPSF #
psfgrid_filename = 'miri_mirim_f560w_fovp101_samp4_npsf4.fits'
if not os.path.exists(psfgrid_filename):
miri = stpsf.MIRI()
miri.filter = 'F560W'
miri.detector = 'MIRIM'
psf_model = miri.psf_grid(num_psfs=4, all_detectors=False, verbose=True, save=True)
else:
psf_model = GriddedPSFModel.read(psfgrid_filename)
psf_model
Running instrument: MIRI, filter: F560W
Running detector: MIRIM
Position 1/4: (0, 0) pixels
Position 1/4 centroid: (np.float64(201.39504365744267), np.float64(201.46837962104274))
Position 2/4: (0, 1023) pixels
Position 2/4 centroid: (np.float64(201.30209346068543), np.float64(201.31984343070144))
Position 3/4: (1023, 0) pixels
Position 3/4 centroid: (np.float64(201.42830769164874), np.float64(201.59926840411683))
Position 4/4: (1023, 1023) pixels
Position 4/4 centroid: (np.float64(201.75498594600967), np.float64(201.4970454286808))
Saving file: miri_mirim_f560w_fovp101_samp4_npsf4.fits
<GriddedPSFModel(flux=1., x_0=0., y_0=0.)>
psf_model.plot_grid()


# get the level 2 image
# here, we'll use the PID 1171 files
path = "./mast/01171/"
level2 = sorted(glob.glob(os.path.join(path, 'jw01171004*cal.fits')))
filename = level2[0]
print(filename)
# load data and convert units from MJy/sr to uJy
with ImageModel(filename) as model:
unit = u.Unit(model.meta.bunit_data)
model.data[model.dq >= 10] = np.nan
data = model.data << unit
error = model.err << unit
pixel_area = pixel_area = model.meta.photometry.pixelarea_steradians * u.sr
data *= pixel_area
error *= pixel_area
data = data.to(u.uJy)
error = error.to(u.uJy)
wcs = model.meta.wcs
data.unit, error.unit
./mast/01171/jw01171004001_02101_00001_mirimage_cal.fits
(Unit("uJy"), Unit("uJy"))
5.3 PSF Photometry #
# translate (x, y) positions from the level 3 image to the level 2 image
xc = found_stars_sel['xcentroid']
yc = found_stars_sel['ycentroid']
sc = wcs_l3.pixel_to_world(xc, yc)
x, y = wcs.world_to_pixel(sc)
init_params = Table()
init_params['x'] = x
init_params['y'] = y
# we need to remove stars in the masked region of
# the level-2 data
mask = x > 404
init_params = init_params[mask]
mask
array([ True, False, True, True, True, True, True, True, True,
False, True, True, True, True, True, True, True, False,
False, True, True, False, True, True, True, False, False,
False, True, False, True, False, False, True, True, True,
False, True, True, False, True, True, True, True, True,
False, True, True, False, True, True, True, True, False,
True, False, True, True, True, False, True, True, False])
# plot the selected stars
norm = simple_norm(data.value, 'sqrt', percent=99)
fig, ax = plt.subplots(figsize=(10, 10))
ax.imshow(data.value, origin='lower', norm=norm)
xypos = zip(init_params['x'], init_params['y'])
aper = CircularAperture(xypos, r=10)
aper.plot(ax, color='red')
plt.show()

fit_shape = 5
localbkg_estimator = LocalBackground(5, 10, bkg_estimator=MMMBackground())
psfphot = PSFPhotometry(psf_model, fit_shape, finder=None, aperture_radius=fit_shape,
localbkg_estimator=localbkg_estimator, progress_bar=True)
phot = psfphot(data, error=error, init_params=init_params)
phot
id | group_id | group_size | local_bkg | x_init | y_init | flux_init | x_fit | y_fit | flux_fit | x_err | y_err | flux_err | npixfit | qfit | cfit | flags |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
uJy | uJy | uJy | uJy | |||||||||||||
int64 | int64 | int64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | int64 | float64 | float64 | int64 |
1 | 1 | 1 | 0.5917736126746966 | 583.6953414360433 | 57.24687010219543 | 64.37585446860986 | 583.6271426055622 | 57.25527770031939 | 22.086381960509662 | 0.009881550234131384 | 0.009997062015888385 | 0.22361477408075406 | 25 | 1.592554525858295 | -0.008029093203134859 | 0 |
2 | 2 | 1 | 0.6100208181015989 | 630.1870920844856 | 77.50324935933168 | 66.95979612654335 | 630.1322550593235 | 77.35470921519108 | 26.07989809910072 | 0.009206323120281227 | 0.009803111243434009 | 0.26646535979914693 | 25 | 1.8008472979147259 | 0.05008110417948685 | 0 |
3 | 3 | 1 | 0.5691058405479137 | 545.155567265627 | 78.01775415078902 | 67.61121880086363 | 545.1085783092715 | 78.00943495517794 | 30.20290385941652 | 0.007770814531898795 | 0.00879892521245536 | 0.27799187555778915 | 25 | 1.3869661801118796 | 0.08939326254907773 | 0 |
4 | 4 | 1 | 0.593688857401901 | 514.4647302272357 | 79.17731661955338 | 63.13382471169785 | 514.3618419546613 | 79.23008476850025 | 24.294878276946108 | 0.009238670171341971 | 0.009431616434272603 | 0.23037622229648375 | 24 | 1.4271814366031326 | 0.00254400481920013 | 1 |
5 | 5 | 1 | 0.6032650537579973 | 526.0810431249562 | 80.86596145105023 | 67.36284381417863 | 525.9712113828396 | 80.89624822108314 | 26.617028281645563 | 0.00857942095488135 | 0.009139997122203222 | 0.2580218388975531 | 25 | 1.4770514988460586 | 0.06073624762697728 | 0 |
6 | 6 | 1 | 0.5452195879137307 | 453.1467736232926 | 84.12057244156529 | 61.86177209688229 | 453.0798262686204 | 84.02618794960281 | 24.453046575420387 | 0.008229781101782904 | 0.008808001067226913 | 0.2213714474830289 | 25 | 2.2921925794144675 | 0.17402357161377432 | 0 |
7 | 7 | 1 | 0.6332202497470021 | 636.5067980659654 | 93.27692547171921 | 66.69100788310536 | 636.4583861214122 | 93.0805291826597 | 23.58011500743861 | 0.009731880876593928 | 0.009559658300160204 | 0.2490521394977686 | 25 | 2.0419826414367943 | 0.1729030083154531 | 0 |
8 | 8 | 1 | 0.6027188777403019 | 656.1494582554864 | 99.97668270363584 | 88.83133597743618 | 656.2523643578978 | 99.95865845658875 | 54.48655531668756 | 0.00524416240204533 | 0.005599566381274772 | 0.32797720995728463 | 25 | 0.7425576584319004 | 0.07986712430142177 | 0 |
9 | 9 | 1 | 0.547520673274994 | 481.54703925766387 | 118.92392090277184 | 56.459257597781644 | 481.48800673642165 | 118.92764364438601 | 19.1782491888176 | 0.010521843238961201 | 0.010579545425558872 | 0.20213058094361303 | 25 | 2.412526246075053 | 0.08655417856521475 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
36 | 36 | 1 | 0.5620971093618923 | 412.2166106708058 | 492.0471019628243 | 68.8067629570188 | 412.2467288371631 | 492.0295971073806 | 32.60878691133045 | 0.006984811247766581 | 0.007054154009861644 | 0.2329917311819081 | 25 | 1.2044795601111933 | 0.07156229957054645 | 0 |
37 | 37 | 1 | 0.5360806073094238 | 603.7650329383015 | 516.3310355219018 | 57.06107361620856 | 603.8016419674484 | 516.4558972595488 | 21.67602670755186 | 0.00887441082565338 | 0.009241322983321627 | 0.19719255380655115 | 25 | 1.8726410278722834 | 0.08225042566395441 | 0 |
38 | 38 | 1 | 0.5449298500494144 | 438.43239918428213 | 517.6858561328448 | 63.63512050110673 | 438.36556392354873 | 517.8102994947366 | 28.61568130285468 | 0.007781994712886895 | 0.007872559012099491 | 0.23308950425313937 | 25 | 1.6292314338781626 | 0.0684033972255797 | 0 |
39 | 39 | 1 | 0.5434614263082806 | 557.926455966104 | 531.9502486117964 | 61.31849260874046 | 558.0156371212586 | 531.9575790458696 | 20.78786146792204 | 0.00911902301788379 | 0.009514214304968042 | 0.20148472945846096 | 25 | 1.4269703915870038 | 0.03015436493065666 | 0 |
40 | 40 | 1 | 0.5319761503161045 | 626.789868315454 | 541.4060866848747 | 55.3254156791539 | 626.815640367721 | 541.3608540990855 | 15.839598349366721 | 0.01138819331808432 | 0.012361404289308334 | 0.18182948752514208 | 25 | 2.475724919321479 | 0.1541262984442095 | 0 |
41 | 41 | 1 | 0.5237871754813839 | 628.1186930495217 | 550.9848648146874 | 53.318885866652614 | 628.111638030972 | 551.0077395394245 | 16.06438745117986 | 0.011450387359860667 | 0.011672388512044371 | 0.18770635400852514 | 25 | 2.2006463348774012 | 0.026898928342503625 | 0 |
42 | 42 | 1 | 0.561615267280857 | 493.2502114845369 | 581.8827941123477 | 59.53039625260884 | 493.2556683895723 | 581.9368573578724 | 21.736153878921936 | 0.009074998292551963 | 0.009287889534871405 | 0.1985728294800299 | 25 | 2.245885366275252 | 0.13960944851282267 | 0 |
43 | 43 | 1 | 0.5316955510606156 | 597.327038102174 | 587.6829662730439 | 61.735091743228274 | 597.4619912123752 | 587.7448120705658 | 25.343537625859778 | 0.00836804812627431 | 0.008521205045241686 | 0.21284260819942533 | 25 | 2.016375429048198 | -0.005845087229945111 | 0 |
44 | 44 | 1 | 0.5456375295271254 | 433.97407354382995 | 606.001088871638 | 58.52389361531568 | 433.9640921192637 | 606.007780305856 | 19.233796064376076 | 0.009871826918899146 | 0.01019920748914034 | 0.191789929450615 | 25 | 1.6630678103751408 | -0.016245994910779434 | 0 |
# convert fit flux from uJy to ABmag
flux = phot['flux_fit']
flux_err = phot['flux_err']
mag = phot['flux_fit'].to(u.ABmag)
magerr = 2.5 * np.log10(1.0 + (flux_err / flux))
magerr = magerr.value * u.ABmag
mag, magerr
(<Magnitude [20.53968855, 20.35923527, 20.19987825, 20.43621318,
20.33710108, 20.42916756, 20.4686352 , 19.55927662,
20.69297761, 20.65126457, 19.32377519, 20.04306398,
20.40416966, 19.70731474, 20.11691711, 20.29396076,
20.44007513, 20.47336615, 20.48695953, 20.12105398,
20.2501405 , 21.16800096, 20.79285496, 20.02802598,
20.33465086, 20.34476846, 19.47693267, 20.36948414,
20.43489364, 20.47643891, 20.41885784, 20.39525343,
20.31342508, 20.14212217, 20.36406716, 20.11666339,
20.56005081, 20.25848977, 20.60547547, 20.90063959,
20.88533957, 20.55704325, 20.39033191, 20.68983748] mag(AB)>,
<Magnitude [0.01093732, 0.01103697, 0.00994756, 0.01024699, 0.01047429,
0.00978486, 0.01140736, 0.00651591, 0.01138331, 0.01133476,
0.0065102 , 0.00798444, 0.00939263, 0.00744215, 0.00802427,
0.00869982, 0.01027089, 0.00948007, 0.00967182, 0.00842352,
0.00898325, 0.01438394, 0.01198467, 0.00790335, 0.00930763,
0.00886982, 0.00599879, 0.0093634 , 0.00927861, 0.00958065,
0.00929012, 0.00903172, 0.00896606, 0.00792852, 0.00901809,
0.00773007, 0.00983257, 0.00880806, 0.01047274, 0.01239263,
0.01261288, 0.00987382, 0.00908026, 0.0107728 ] mag(AB)>)
# Write to File
df = DataFrame({"RA": sc.ra.deg[mask], "DEC": sc.dec.deg[mask], "Mag": mag.value, "Mag Err": magerr.value})
df.to_csv('miri_photometry_photutils.txt', index=False)
