Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JP-3896: Deprecate or remove various assign_wcs utility functions #9221

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions changes/9221.assign_wcs.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate util.reproject and remove some private util functions
20 changes: 2 additions & 18 deletions jwst/assign_wcs/tests/test_nircam.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"""
import numpy as np
import pytest
import re


from astropy.io import fits
Expand All @@ -21,6 +20,7 @@
from jwst.assign_wcs.assign_wcs_step import AssignWcsStep
from jwst.assign_wcs import nircam
from jwst.assign_wcs import util
from stcal.alignment.util import sregion_to_footprint


# Allowed settings for nircam
Expand Down Expand Up @@ -247,22 +247,6 @@ def test_wfss_sip():
assert key in wfss_model.meta.wcsinfo.instance


def _sregion_to_footprint(s_region):
"""
Parameters
----------
s_region : str
The S_REGION header keyword

Returns
-------
footprint : np.array
A 2D array of the footprint of the region, shape (N, 2)
"""
no_prefix = re.sub(r"[a-zA-Z]", "", s_region)
return np.array(no_prefix.split(), dtype=float).reshape(-1, 2)


def test_update_s_region_imaging():
"""Ensure the s_region keyword matches output of wcs.footprint()"""
model = ImageModel(create_hdul())
Expand All @@ -271,5 +255,5 @@ def test_update_s_region_imaging():

s_region = model.meta.wcsinfo.s_region
footprint = model.meta.wcs.footprint().flatten()
footprint_sregion = _sregion_to_footprint(s_region).flatten()
footprint_sregion = sregion_to_footprint(s_region).flatten()
assert np.allclose(footprint, footprint_sregion, rtol=1e-9)
132 changes: 12 additions & 120 deletions jwst/assign_wcs/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import logging
import functools
import numpy as np
import warnings

from astropy.coordinates import SkyCoord
from astropy.io import fits
from astropy.modeling import models as astmodels
from astropy.table import QTable
from astropy.constants import c
Expand Down Expand Up @@ -64,16 +64,12 @@
super().__init__(64, message)


def _domain_to_bounding_box(domain):
# TODO: remove this when domain is completely removed
bb = tuple([(item['lower'], item['upper']) for item in domain])
if len(bb) == 1:
bb = bb[0]
return bb


def reproject(wcs1, wcs2):
"""
.. deprecated:: 1.17.2
:py:func:`reproject()` has been deprecated and will be removed
in a future release. Use :py:func:`stcal.alignment.util.reproject` instead.

Given two WCSs return a function which takes pixel coordinates in
the first WCS and computes their location in the second one.

Expand All @@ -91,6 +87,13 @@
Function to compute the transformations. It takes x, y
positions in ``wcs1`` and returns x, y positions in ``wcs2``.
"""
warnings.warn(

Check warning on line 90 in jwst/assign_wcs/util.py

View check run for this annotation

Codecov / codecov/patch

jwst/assign_wcs/util.py#L90

Added line #L90 was not covered by tests
"'reproject()' has been deprecated since 1.17.2 and "
"will be removed in a future release. "
"Use 'stcal.alignment.util.reproject()' instead.",
DeprecationWarning,
stacklevel=2
)

def _reproject(x, y):
sky = wcs1.forward_transform(x, y)
Expand Down Expand Up @@ -196,101 +199,6 @@
return [pc1_1, pc1_2, pc2_1, pc2_2]


def compute_fiducial(wcslist, bounding_box=None):
"""
For a celestial footprint this is the center.
For a spectral footprint, it is the beginning of the range.

This function assumes all WCSs have the same output coordinate frame.
"""

axes_types = wcslist[0].output_frame.axes_type
spatial_axes = np.array(axes_types) == 'SPATIAL'
spectral_axes = np.array(axes_types) == 'SPECTRAL'
footprints = np.hstack([w.footprint(bounding_box=bounding_box).T for w in wcslist])
spatial_footprint = footprints[spatial_axes]
spectral_footprint = footprints[spectral_axes]

fiducial = np.empty(len(axes_types))
if spatial_footprint.any():
lon, lat = spatial_footprint
lon, lat = np.deg2rad(lon), np.deg2rad(lat)
x = np.cos(lat) * np.cos(lon)
y = np.cos(lat) * np.sin(lon)
z = np.sin(lat)

x_mid = (np.max(x) + np.min(x)) / 2.
y_mid = (np.max(y) + np.min(y)) / 2.
z_mid = (np.max(z) + np.min(z)) / 2.
lon_fiducial = np.rad2deg(np.arctan2(y_mid, x_mid)) % 360.0
lat_fiducial = np.rad2deg(np.arctan2(z_mid, np.sqrt(x_mid ** 2 + y_mid ** 2)))
fiducial[spatial_axes] = lon_fiducial, lat_fiducial
if spectral_footprint.any():
fiducial[spectral_axes] = spectral_footprint.min()
return fiducial


def is_fits(input_img):
"""
Returns
--------
isFits: tuple
An ``(isfits, fitstype)`` tuple. The values of ``isfits`` and
``fitstype`` are specified as:

- ``isfits``: True|False
- ``fitstype``: if True, one of 'waiver', 'mef', 'simple'; if False, None

Notes
-----
Input images which do not have a valid FITS filename will automatically
result in a return of (False, None).

In the case that the input has a valid FITS filename but runs into some
error upon opening, this routine will raise that exception for the calling
routine/user to handle.
"""

isfits = False
fitstype = None
names = ['fits', 'fit', 'FITS', 'FIT']
# determine if input is a fits file based on extension
# Only check type of FITS file if filename ends in valid FITS string
f = None
fileclose = False
if isinstance(input_img, fits.HDUList):
isfits = True
f = input_img
else:
isfits = True in [input_img.endswith(suffix) for suffix in names]

# if input is a fits file determine what kind of fits it is
# waiver fits len(shape) == 3
if isfits:
if not f:
try:
f = fits.open(input_img, mode='readonly')
fileclose = True
except Exception:
if f is not None:
f.close()
raise
data0 = f[0].data
if data0 is not None:
try:
if isinstance(f[1], fits.TableHDU):
fitstype = 'waiver'
except IndexError:
fitstype = 'simple'

else:
fitstype = 'mef'
if fileclose:
f.close()

return isfits, fitstype


def subarray_transform(input_model):
"""
Return an offset model if the observation uses a subarray.
Expand Down Expand Up @@ -705,22 +613,6 @@
return final_objects


def get_num_msa_open_shutters(shutter_state):
"""
Return the number of open shutters in a slitlet.

Parameters
----------
shutter_state : str
``Slit.shutter_state`` attribute - a combination of
``1`` - open shutter, ``0`` - closed shutter, ``x`` - main shutter.
"""
num = shutter_state.count('1')
if 'x' in shutter_state:
num += 1
return num


def transform_bbox_from_shape(shape, order="C"):
"""Create a bounding box from the shape of the data.

Expand Down
8 changes: 4 additions & 4 deletions jwst/resample/tests/test_resample_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from jwst.datamodels import ModelContainer, ModelLibrary
from jwst.assign_wcs import AssignWcsStep
from jwst.assign_wcs.util import compute_fiducial, compute_scale
from jwst.assign_wcs.util import compute_scale
from jwst.exp_to_source import multislit_to_container
from jwst.extract_2d import Extract2dStep
from jwst.resample import ResampleSpecStep, ResampleStep
Expand Down Expand Up @@ -1179,14 +1179,14 @@ def test_custom_wcs_pscale_resample_imaging(nircam_rate, ratio):
im = AssignWcsStep.call(nircam_rate, sip_approx=False)
im.data += 5

fiducial = compute_fiducial([im.meta.wcs])
input_scale = compute_scale(wcs=im.meta.wcs, fiducial=fiducial)
crval = (22.04019, 11.98262)
input_scale = compute_scale(wcs=im.meta.wcs, fiducial=crval)
result = ResampleStep.call(
im,
pixel_scale_ratio=ratio,
pixel_scale=3600 * input_scale * 0.75
)
output_scale = compute_scale(wcs=result.meta.wcs, fiducial=fiducial)
output_scale = compute_scale(wcs=result.meta.wcs, fiducial=crval)

# test scales are close
assert np.allclose(output_scale, input_scale * 0.75)
Expand Down