Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,12 @@ the 'main' branch.
runs several different checks including running the unit tests, ensuring
the documentation builds, checking for code style issues (see the [PEP8](https://peps.python.org/pep-0008/) style guide),
and ensuring any changes are covered by unit tests. The CI runs upon opening
a PR, and will re-run any time you push commits to that branch.
* You will need to add a change log entry in CHANGES.rst if your contribution
is a new feature or bug fix. An entry is not required for small fixes like typos.
a PR, and will re-run any time you push commits to that branch.
* Our code style checker uses [ruff](https://docs.astral.sh/ruff/), and using
`ruff check` locally can be helpful to identify style issues before opening a PR.
* You will need to add a change log entry in changes/PRID.fragmenttype.rst
if your contribution is a new feature or bug fix.
An entry is not required for small fixes like typos.
* Your PR will need to be reviewed and approved by at least two maintainers.
They may require changes from you before your code can be merged, in which
case you will need to go back and make these changes and push them (they will
Expand Down
1 change: 1 addition & 0 deletions changes/9076.general.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added more code style rules
16 changes: 8 additions & 8 deletions jwst/ami/ami_analyze_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ def override_bandpass(self):
"""
Read bandpass from asdf file and use it to override the default.

Expects an array of [effstims, wave_m]
Expects an array of [effstims, wave_m]
(i.e. np.array((effstims,wave_m)).T) stored as 'bandpass' in asdf file,
where effstims are normalized countrates (unitless) and wave_m are the
wavelengths across the filter at which to compute the model (meters).

Returns
-------
bandpass: array
Expand All @@ -65,21 +65,21 @@ def override_bandpass(self):
# assume it is an array of the correct shape
wavemin = np.min(bandpass[:,1])
wavemax = np.max(bandpass[:,1])
self.log.info('User-defined bandpass provided:')
self.log.info('User-defined bandpass provided:')
self.log.info('\tOVERWRITING ALL NIRISS-SPECIFIC FILTER/BANDPASS VARIABLES')
self.log.info(f'Using {bandpass.shape[0]} wavelengths for fit.')
self.log.info(f'Wavelength min: {wavemin:.3e} \t Wavelength max: {wavemax:.3e}')

# update attribute and return
self.bandpass = bandpass
self.bandpass = bandpass
return bandpass

except FileNotFoundError:
message = f'File {self.bandpass} could not be found at the specified location.'
raise Exception(message)

except KeyError:
message1 = 'ASDF file does not contain the required "bandpass" key. '
message1 = 'ASDF file does not contain the required "bandpass" key. '
message2 = 'See step documentation for info on creating a custom bandpass ASDF file.'
raise Exception((message1 + message2))

Expand All @@ -90,9 +90,9 @@ def override_bandpass(self):

def override_affine2d(self):
"""
Read user-input affine transform from ASDF file.
Read user-input affine transform from ASDF file.

Makes an Affine2d object (see utils.Affine2D class).
Makes an Affine2d object (see utils.Affine2D class).
Input should contain mx,my,sx,sy,xo,yo,rotradccw.
"""
try:
Expand All @@ -117,7 +117,7 @@ def override_affine2d(self):
affine2d = None

except KeyError:
message1 = 'ASDF file does not contain all of the required keys: mx, my, sx, sy ,xo, yo, rotradccw. '
message1 = 'ASDF file does not contain all of the required keys: mx, my, sx, sy ,xo, yo, rotradccw. '
message2 = 'See step documentation for info on creating a custom affine2d ASDF file.'
self.log.info((message1 + message2))
self.log.info('\t **** DEFAULTING TO USE IDENTITY TRANSFORM ****')
Expand Down
8 changes: 4 additions & 4 deletions jwst/ami/bp_fix.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ def fourier_corr(data, pxdq, fmas):

References
----------
M. J. Ireland, Phase errors in diffraction-limited imaging: contrast limits
for sparse aperture masking, Monthly Notices of the Royal Astronomical
Society, Volume 433, Issue 2, 01 August 2013, Pages 1718–1728,
https://doi.org/10.1093/mnras/stt859
M. J. Ireland, Phase errors in diffraction-limited imaging: contrast limits
for sparse aperture masking, Monthly Notices of the Royal Astronomical
Society, Volume 433, Issue 2, 01 August 2013, Pages 1718–1728,
https://doi.org/10.1093/mnras/stt859
"""

# Get the dimensions.
Expand Down
4 changes: 2 additions & 2 deletions jwst/ami/instrument_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ def __init__(self,
"""
Initialize NIRISS class for NIRISS/AMI instrument.

Module for defining all instrument characteristics including data format,
Module for defining all instrument characteristics including data format,
wavelength info, and mask geometry.

Parameters
----------
filt: string
filter name

nrm_model: NRMModel datamodel
datamodel containing mask geometry information

Expand Down
12 changes: 6 additions & 6 deletions jwst/ami/lg_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@

class LgModel:
"""
A class for conveniently dealing with an "NRM object."
A class for conveniently dealing with an "NRM object."

This should be able to take an NRMDefinition object for mask geometry.
Defines mask geometry and detector-scale parameters.
Simulates PSF (broadband or monochromatic)
Expand Down Expand Up @@ -195,8 +195,8 @@ def make_model(
"""
Generates the fringe model.

Use the attributes of the object with a bandpass that is either a single
wavelength or a list of tuples of the form
Use the attributes of the object with a bandpass that is either a single
wavelength or a list of tuples of the form
[(weight1, wavl1), (weight2, wavl2),...]. The model is
a collection of fringe intensities, where nholes = 7 means the model
has a @D slice for each of 21 cosines, 21 sines, a DC-like, and a flux
Expand Down Expand Up @@ -300,7 +300,7 @@ def fit_image(
"""
Run a least-squares fit on an input image.

Find the appropriate wavelength scale and rotation.
Find the appropriate wavelength scale and rotation.
If a model is not specified then this
method will find the appropriate wavelength scale, rotation (and
hopefully centering as well -- This is not written into the object yet,
Expand Down Expand Up @@ -425,7 +425,7 @@ def improve_scaling(
self, img, scaleguess=None, rotstart=0.0, centering="PIXELCENTERED"
):
"""
Determine the scale and rotation that best fits the data.
Determine the scale and rotation that best fits the data.

Correlations
are calculated in the image plane, in anticipation of data with many
Expand Down
208 changes: 104 additions & 104 deletions jwst/ami/mask_definition_ami.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,108 +5,108 @@

class NRMDefinition():

def __init__(self, nrm_model, maskname='jwst_ami', chooseholes=None):
"""
Set attributes of NRMDefinition class.

Get hole centers and other mask geometry details from NRMModel, apply rotations/flips
as necessary and set them as attributes.

Parameters
----------
nrm_model: NRMModel
datamodel containing NRM reference file data
maskname: string
Identifier for mask geometry; default 'jwst_ami', optional
chooseholes: list
None, or e.g. ['B2', 'B4', 'B5', 'B6'] for a four-hole mask, optional
If None, use real seven-hole mask
"""

if maskname not in ['jwst_ami','jwst_g7s6c']:
raise ValueError("Mask name not supported")

self.maskname = maskname # there's only one mask but this is used in oifits
self.hdia = nrm_model.flat_to_flat
self.activeD = nrm_model.diameter
self.OD = nrm_model.pupil_circumscribed
self.ctrs = []

self.read_nrm_model(nrm_model, chooseholes=chooseholes)

def read_nrm_model(self, nrm_model, chooseholes=None):
"""
Calculate hole centers with appropriate rotation.

Parameters
----------
nrm_model: NRMModel
datamodel containing NRM reference file data
chooseholes: list
None, or e.g. ['B2', 'B4', 'B5', 'B6'] for a four-hole mask

Returns
-------
f2f: float
flat-to-flat distance of mask holes
ctrs_asbuilt: array
Actual hole centers [meters]
"""

ctrs_asdesigned = np.array([[nrm_model.x_a1, nrm_model.y_a1], # B4 -> B4
[nrm_model.x_a2, nrm_model.y_a2], # C5 -> C2
[nrm_model.x_a3, nrm_model.y_a3], # B3 -> B5
[nrm_model.x_a4, nrm_model.y_a4], # B6 -> B2
[nrm_model.x_a5, nrm_model.y_a5], # C6 -> C1
[nrm_model.x_a6, nrm_model.y_a6], # B2 -> B6
[nrm_model.x_a7, nrm_model.y_a7]]) # C1 -> C6



holedict = {} # as_built names, C2 open, C5 closed, but as designed coordinates
# Assemble holes by actual open segment names (as_built). Either the full mask or the
# subset-of-holes mask will be V2-reversed after the as_designed centers are defined
# Debug orientations with b4,c6,[c2]
allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')

for hole, coords in zip(allholes,ctrs_asdesigned):
holedict[hole] = coords

if chooseholes: # holes B4 B5 C6 asbuilt for orientation testing
holelist = []
for h in allholes:
if h in chooseholes:
holelist.append(holedict[h])
ctrs_asdesigned = np.array(holelist)

ctrs_asbuilt = ctrs_asdesigned.copy()

# create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
# eg maps open hole C5 in as_designed to C2 as_built, eg C4 unaffected....
ctrs_asbuilt[:, 0] *= -1

# LG++ rotate hole centers by 90 deg to match MAST o/p DMS PSF with
# no affine2d transformations 8/2018 AS
# LG++ The above aligns the hole pattern with the hex analytic FT,
# flat top & bottom as seen in DMS data. 8/2018 AS
ctrs_asbuilt = rotate2dccw(ctrs_asbuilt, np.pi / 2.0) # overwrites attributes

# create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
self.ctrs = ctrs_asbuilt

def showmask(self):
"""
Calculate the diameter of the smallest centered circle (D)
enclosing the live mask area

Returns
-------
Diameter of the smallest centered circle

"""
radii = []
for ctr in self.ctrs:
radii.append(math.sqrt(ctr[0] * ctr[0] + ctr[1] * ctr[1]))

return 2.0 * (max(radii) + 0.5 * self.hdia)
def __init__(self, nrm_model, maskname='jwst_ami', chooseholes=None):
"""
Set attributes of NRMDefinition class.

Get hole centers and other mask geometry details from NRMModel, apply rotations/flips
as necessary and set them as attributes.

Parameters
----------
nrm_model: NRMModel
datamodel containing NRM reference file data
maskname: string
Identifier for mask geometry; default 'jwst_ami', optional
chooseholes: list
None, or e.g. ['B2', 'B4', 'B5', 'B6'] for a four-hole mask, optional
If None, use real seven-hole mask
"""

if maskname not in ['jwst_ami','jwst_g7s6c']:
raise ValueError("Mask name not supported")

self.maskname = maskname # there's only one mask but this is used in oifits
self.hdia = nrm_model.flat_to_flat
self.activeD = nrm_model.diameter
self.OD = nrm_model.pupil_circumscribed
self.ctrs = []

self.read_nrm_model(nrm_model, chooseholes=chooseholes)

def read_nrm_model(self, nrm_model, chooseholes=None):
"""
Calculate hole centers with appropriate rotation.

Parameters
----------
nrm_model: NRMModel
datamodel containing NRM reference file data
chooseholes: list
None, or e.g. ['B2', 'B4', 'B5', 'B6'] for a four-hole mask

Returns
-------
f2f: float
flat-to-flat distance of mask holes
ctrs_asbuilt: array
Actual hole centers [meters]
"""

ctrs_asdesigned = np.array([[nrm_model.x_a1, nrm_model.y_a1], # B4 -> B4
[nrm_model.x_a2, nrm_model.y_a2], # C5 -> C2
[nrm_model.x_a3, nrm_model.y_a3], # B3 -> B5
[nrm_model.x_a4, nrm_model.y_a4], # B6 -> B2
[nrm_model.x_a5, nrm_model.y_a5], # C6 -> C1
[nrm_model.x_a6, nrm_model.y_a6], # B2 -> B6
[nrm_model.x_a7, nrm_model.y_a7]]) # C1 -> C6



holedict = {} # as_built names, C2 open, C5 closed, but as designed coordinates
# Assemble holes by actual open segment names (as_built). Either the full mask or the
# subset-of-holes mask will be V2-reversed after the as_designed centers are defined
# Debug orientations with b4,c6,[c2]
allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')

for hole, coords in zip(allholes,ctrs_asdesigned):
holedict[hole] = coords

if chooseholes: # holes B4 B5 C6 asbuilt for orientation testing
holelist = []
for h in allholes:
if h in chooseholes:
holelist.append(holedict[h])
ctrs_asdesigned = np.array(holelist)

ctrs_asbuilt = ctrs_asdesigned.copy()

# create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
# eg maps open hole C5 in as_designed to C2 as_built, eg C4 unaffected....
ctrs_asbuilt[:, 0] *= -1

# LG++ rotate hole centers by 90 deg to match MAST o/p DMS PSF with
# no affine2d transformations 8/2018 AS
# LG++ The above aligns the hole pattern with the hex analytic FT,
# flat top & bottom as seen in DMS data. 8/2018 AS
ctrs_asbuilt = rotate2dccw(ctrs_asbuilt, np.pi / 2.0) # overwrites attributes

# create 'live' hole centers in an ideal, orthogonal undistorted xy pupil space,
self.ctrs = ctrs_asbuilt

def showmask(self):
"""
Calculate the diameter of the smallest centered circle (D)
enclosing the live mask area

Returns
-------
Diameter of the smallest centered circle

"""
radii = []
for ctr in self.ctrs:
radii.append(math.sqrt(ctr[0] * ctr[0] + ctr[1] * ctr[1]))

return 2.0 * (max(radii) + 0.5 * self.hdia)

Loading
Loading