Skip to content

Commit

Permalink
Merge pull request #693 from mperrin/tune_detector_effects
Browse files Browse the repository at this point in the history
Tune detector effects model parameters to better match measured ePSFs
  • Loading branch information
obi-wan76 authored Jul 26, 2023
2 parents 49cdb30 + 681472c commit b219a7d
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 12 deletions.
17 changes: 11 additions & 6 deletions webbpsf/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,22 @@
# Note, these are parameterized as arcseconds for convenience (and consistency with the jitter paramater)
# but the underlying physics cares more about detector pixel pitch.
INSTRUMENT_DETECTOR_CHARGE_DIFFUSION_DEFAULT_PARAMETERS = {
'NIRCAM_SW': 0.006, # Fit by Marcio to WFS TA ePSFs
'NIRCAM_LW': 0.012, # Scaled up by pixel pitch
'NIRISS': 0.028, # Fit by Marcio to MIMF-3 F158M (ePSF)
'NIRCAM_SW': 0.0062, # Fit by Marcio to WFS TA ePSFs, and by Marshall to prelim NIRCam SW ePSFs by J. Anderson
'NIRCAM_LW': 0.018, # Fit by Marshall to prelim LW ePSFs by J. Anderson
'NIRISS': 0.0202, # Fit by Marcio to MIMF-3 F158M (ePSF), and by Marshall to NIRISS ePSFs by Anderson & Libralato
'FGS': 0.07, # Fit by Marcio to FGS_ID images
'NIRSPEC': 0.036,
'MIRI': 0.05, # Fit by Marcio to F560W ePSF and single PSF (MIMF-3)
# 0.070 Based on user reports, see issue #674. However, this is before adding IPC effects
'MIRI': 0.001, # Fit by Marshall + Marcio to ePSFs, after adding IPC
# 0.070 Based on user reports, see issue #674. However, this was before adding IPC effects
}
# add Interpixel capacitance (IPC) effects. These are the parameters for each detector kernel
# For NIRCam we use CV3/Flight convolution kernels from Jarron Leisenring, see detectors.apply_detector_ipc for details
# NIRISS has different kernels provided by Kevin Volk (STScI), see detectors.apply_detector_ipc for details
INSTRUMENT_IPC_DEFAULT_KERNEL_PARAMETERS = {
'MIRI': (0.033, 0.024, 0.013), # Based on JWST-STScI-002925 by Mike Engesser
}
}

# How many detector pixels to mask out for the inner "hole" in the cruciform?
# See Gaspar et al. 2021 for illustrative figures.
# This is a rough approximation of a detector-position-dependent phenomenon
MIRI_CRUCIFORM_INNER_RADIUS_PIX = 12
8 changes: 7 additions & 1 deletion webbpsf/detectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np
import scipy
import webbpsf
from webbpsf import utils
from webbpsf import utils, constants
from astropy.convolution.kernels import CustomKernel
from astropy.convolution import convolve
from astropy.io import fits
Expand Down Expand Up @@ -309,6 +309,9 @@ def _make_miri_scattering_kernel(image, amplitude, nsamples):
# Create 1d kernel
kernel_x = amplitude * np.exp(-np.abs(x) / 25)

# reduce intensity in the inner part, since the cruciform is suppressed at small radii
kernel_x[np.abs(x) < constants.MIRI_CRUCIFORM_INNER_RADIUS_PIX] *= 0.5

# Reshape kernel to 2D image for use in convolution
kernel_x.shape = (1, image.shape[1])

Expand Down Expand Up @@ -412,6 +415,9 @@ def apply_miri_scattering(hdulist_or_filename=None, kernel_amp=None):
# and https://github.com/spacetelescope/webbpsf/issues/415
kernel_amp_corrections = {'F560W': 4.05, 'F770W': 4.1, 'F1000W': 3.8,
'F1130W': 2.5, 'F1280W': 2.5, 'F1065C': 2.5, 'F1140C': 2.5}
# In-flight correction based on measured cycle 1 ePSFs, coarsely
for k in kernel_amp_corrections:
kernel_amp_corrections[k] *= 0.5

# Set values if not already set by a keyword argument
if kernel_amp is None:
Expand Down
23 changes: 18 additions & 5 deletions webbpsf/gridded_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CreatePSFLibrary:

def __init__(self, instrument, filter_name, detectors="all", num_psfs=16, psf_location=None,
use_detsampled_psf=False, save=True, outdir=None, filename=None, overwrite=True, verbose=True,
psf_location_list=None,
**kwargs):
"""
Description
Expand Down Expand Up @@ -61,6 +62,10 @@ def __init__(self, instrument, filter_name, detectors="all", num_psfs=16, psf_lo
If num_psfs = 1, then this is used to set the (y,x) location of that PSF.
Default is the center point for the detector.
psf_location_list: list of tuples
If num_psfs > 1, then this should be a list of locations for each PSF.
This can be used to set irregular sampling, if needed for some reason.
use_detsampled_psf : bool
If True, the grid of PSFs returned will be detector sampled (made by binning
down the oversampled PSF). If False, the PSFs will be oversampled by the
Expand Down Expand Up @@ -128,7 +133,7 @@ def __init__(self, instrument, filter_name, detectors="all", num_psfs=16, psf_lo
self.detector_list = self._set_detectors(self.filter, detectors)

# Set the locations on the detector of the fiducial PSFs
self.location_list = self._set_psf_locations(num_psfs, psf_location)
self.location_list = self._set_psf_locations(num_psfs, psf_location, psf_location_list)

# Set PSF attributes for the 3 kwargs that will be used before the calc_psf() call
if "add_distortion" in kwargs:
Expand Down Expand Up @@ -192,7 +197,7 @@ def _set_detectors(self, filt, detectors):

return det

def _set_psf_locations(self, num_psfs, psf_location):
def _set_psf_locations(self, num_psfs, psf_location, psf_location_list):
"""Set the locations on the detector of the fiducial PSFs"""

self.num_psfs = num_psfs
Expand All @@ -207,9 +212,17 @@ def _set_psf_locations(self, num_psfs, psf_location):
# Want this case to be at the specified location
location_list = [(psf_location[::-1])] # tuple of (x,y)
else:
max_size = self.webb._detector_npixels - 1
loc_list = [int(round(num * max_size)) for num in np.linspace(0, 1, self.length, endpoint=True)]
location_list = list(itertools.product(loc_list, loc_list)) # list of tuples (x,y) (for WebbPSF)

if psf_location_list is not None:
if len(psf_location_list) != num_psfs:
raise ValueErrorf(
"Length of psf_location_list ({len(psf_location_list)}) must equal num_psfs ({num_psfs})")
location_list = psf_location_list

else:
max_size = self.webb._detector_npixels - 1
loc_list = [int(round(num * max_size)) for num in np.linspace(0, 1, self.length, endpoint=True)]
location_list = list(itertools.product(loc_list, loc_list)) # list of tuples (x,y) (for WebbPSF)

return location_list

Expand Down

0 comments on commit b219a7d

Please sign in to comment.