diff --git a/changes/9221.assign_wcs.rst b/changes/9221.assign_wcs.rst new file mode 100644 index 0000000000..b9670e2f1a --- /dev/null +++ b/changes/9221.assign_wcs.rst @@ -0,0 +1 @@ +Deprecate util.reproject and remove some private util functions diff --git a/jwst/assign_wcs/tests/test_nircam.py b/jwst/assign_wcs/tests/test_nircam.py index b8ddd71f83..c06fd056a3 100644 --- a/jwst/assign_wcs/tests/test_nircam.py +++ b/jwst/assign_wcs/tests/test_nircam.py @@ -10,7 +10,6 @@ """ import numpy as np import pytest -import re from astropy.io import fits @@ -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 @@ -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()) @@ -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) diff --git a/jwst/assign_wcs/util.py b/jwst/assign_wcs/util.py index 695f966502..2c35b8a319 100644 --- a/jwst/assign_wcs/util.py +++ b/jwst/assign_wcs/util.py @@ -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 @@ -64,16 +64,12 @@ def __init__(self, message=None): 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. @@ -91,6 +87,13 @@ def reproject(wcs1, wcs2): Function to compute the transformations. It takes x, y positions in ``wcs1`` and returns x, y positions in ``wcs2``. """ + warnings.warn( + "'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) @@ -196,101 +199,6 @@ def calc_rotation_matrix(roll_ref: float, v3i_yang: float, vparity: int = 1) -> 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. @@ -705,22 +613,6 @@ def _create_grism_bbox(input_model, mmag_extract=None, wfss_extract_half_height= 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. diff --git a/jwst/resample/tests/test_resample_step.py b/jwst/resample/tests/test_resample_step.py index 558e6f0f16..c4c4ff6333 100644 --- a/jwst/resample/tests/test_resample_step.py +++ b/jwst/resample/tests/test_resample_step.py @@ -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 @@ -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)