Source code for jwst.ami.hextransformee
# Module for calculation of the hexagon-aperture PSFs
import numpy as np
__all__ = ["gfunction", "hextransform"]
[docs]
def gfunction(xi, eta, c, pixel, d, lam, affine2d, minus=False):
"""
Fourier transform a half-hexagon.
By half-hexagon, it is meant that
the hexagon is bisected from one corner to its diametrically opposite corner.
Parameters
----------
xi : 2D float array
Hexagon's coordinate center at center of symmetry, along flat edge
eta : 2D float array
Hexagon's coordinate center at center of symmetry, normal to xi
c : tuple(float, float), required
Coordinates of center
pixel : float, required
Pixel scale
d : float, required
Flat-to-flat distance across hexagon
lam : float, required
Wavelength
affine2d : Affine2d object, required
Distortion object
minus : bool, required
If True, use flipped sign of xi in calculation
Returns
-------
2D complex array
Fourier transform of one half of a hexagon.
"""
xi = (d / lam) * pixel * (xi - c[0])
eta = (d / lam) * pixel * (eta - c[1])
i = 1j
pi = np.pi
xip, etap = affine2d.distort_f_args(xi, eta)
if minus:
xip = -1 * xip
g = (
np.exp(-i * pi * (2 * etap / np.sqrt(3) + xip))
* (
(np.sqrt(3) * etap - 3 * xip)
* (np.exp(i * pi * np.sqrt(3) * etap) - np.exp(i * pi * (4 * etap / np.sqrt(3) + xip)))
+ (np.sqrt(3) * etap + 3 * xip)
* (np.exp(i * pi * etap / np.sqrt(3)) - np.exp(i * pi * xip))
)
/ (4 * pi * pi * (etap * etap * etap - 3 * etap * xip * xip))
)
return g * affine2d.distortphase(xi, eta)
[docs]
def hextransform(s, d, lam, pitch, affine2d, c=None):
"""
Calculate the complex array analytical transform of a (distorted if necessary) hexagon.
Parameters
----------
s : (int,int) tuple, required
Size of output hexagonal beam in pixels
d : float, required
Flat-to-flat distance across hexagon in meters
lam : float, required
Wavelength of the observation in meters
pitch : float, required
Sampling pitch in radians in image plane
affine2d : Affine2d object
Distortion object
c : (float,float) tuple, optional
Location of center of hexagonal primary beam in pixels.
If None, the center is assumed to be at the center of the array.
Returns
-------
hex_complex : 2D complex array
Complex array analytical transform of a hexagon
"""
if c is None:
c = [float(s[0]) / 2.0 - 0.5, float(s[1]) / 2.0 - 0.5]
# deal with central pixel singularity:
c_adjust = [None, None]
eps_offset = 1.0e-8
# The fractional part of the offsets:
d0, d1 = (c[0] - int(c[0]), c[1] - int(c[1]))
# Are they very small (i.e. 'almost exactly' centered on 0)?
if abs(d0) < 0.5 * eps_offset: # might have the singular central pixel here
c_adjust[0] = c[0] + eps_offset
else:
c_adjust[0] = c[0]
if abs(d1) < 0.5 * eps_offset: # might have the singular central pixel here
c_adjust[1] = c[1] + eps_offset
else:
c_adjust[1] = c[1]
hex_complex = np.fromfunction(
gfunction,
s,
d=d,
c=c_adjust,
lam=lam,
pixel=pitch,
affine2d=affine2d,
minus=False,
) + np.fromfunction(
gfunction,
s,
d=d,
c=c_adjust,
lam=lam,
pixel=pitch,
affine2d=affine2d,
minus=True,
)
# The center pixel is singular, so we replace it with the known value of sqrt(3)/2
hex_complex[int(c[0]), int(c[1])] = np.sqrt(3) / 2.0
return hex_complex