Skip to content

Commit

Permalink
Merge pull request #421 from spacetelescope/0.18.2x
Browse files Browse the repository at this point in the history
0.18.2x
  • Loading branch information
nden authored Sep 7, 2022
2 parents 2b92305 + da17d1b commit e8209c0
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 77 deletions.
18 changes: 18 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
0.18.2 (2022-09-07)
-------------------
Bug Fixes
^^^^^^^^^

- Corrected the reported requested forward SIP accuracy and reported fit
residuals by ``to_fits_sip()`` and ``to_fits()``. [#413, #419]

- Fixed a bug due to which the check for divergence in ``_fit_2D_poly()`` and
hence in ``to_fits()`` and ``to_fits_sip()`` was ignored. [#414]

New Features
^^^^^^^^^^^^

0.18.1 (2022-03-15)
-------------------
Bug Fixes
Expand All @@ -13,6 +27,10 @@ Bug Fixes
- Updated code in ``region.py`` with latest improvements and bug fixes
from ``stsci.skypac.regions.py`` [#382]

- Added support to ``_compute_lon_pole()`` for computation of ``lonpole``
for all projections from ``astropy.modeling.projections``. This also
extends support for different projections in ``wcs_from_fiducial()``. [#389]

New Features
^^^^^^^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _gwcs:

GWCS Documentation
==================

Expand Down
13 changes: 9 additions & 4 deletions gwcs/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,15 @@ def world_to_pixel(self, *world_objects):
Convert world coordinates to pixel values.
"""
result = self.invert(*world_objects, with_units=True)
if not utils.isnumerical(result[0]):
result = [i.value for i in result]
if self.input_frame.naxes == 1:
return result[0]

if self.input_frame.naxes > 1:
first_res = result[0]
if not utils.isnumerical(first_res):
result = [i.value for i in result]
else:
if not utils.isnumerical(result):
result = result.value

return result

def world_to_array_index(self, *world_objects):
Expand Down
7 changes: 0 additions & 7 deletions gwcs/converters/tests/test_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# -*- coding: utf-8 -*-
import os.path
import pytest
import warnings

astropy = pytest.importorskip('astropy', minversion='3.0')

Expand Down Expand Up @@ -103,12 +102,6 @@ def test_composite_frame(tmpdir):
def create_test_frames():
"""Creates an array of frames to be used for testing."""

# Suppress warnings from astropy that are caused by having 'dubious' dates
# that are too far in the future. It's not a concern for the purposes of
# unit tests. See issue #5809 on the astropy GitHub for discussion.
from astropy._erfa import ErfaWarning
warnings.simplefilter("ignore", ErfaWarning)

frames = [
cf.CelestialFrame(reference_frame=coord.ICRS()),

Expand Down
2 changes: 2 additions & 0 deletions gwcs/coordinate_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ def axes_type(self):
def coordinates(self, *args):
""" Create world coordinates object"""
coo = tuple([arg * un if not hasattr(arg, "to") else arg.to(un) for arg, un in zip(args, self.unit)])
if self.naxes == 1:
return coo[0]
return coo

def coordinate_to_quantity(self, *coords):
Expand Down
20 changes: 20 additions & 0 deletions gwcs/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
from astropy import time
from astropy import coordinates as coord
from astropy.wcs.wcsapi import HighLevelWCSWrapper
import astropy.modeling.models as m
import gwcs.coordinate_frames as cf
import gwcs


# Shorthand the name of the 2d gwcs fixture
Expand Down Expand Up @@ -492,3 +494,21 @@ def test_composite_many_base_frame():

assert len(wao_components) == 2
assert not {c[0] for c in wao_components}.difference({"SPATIAL", "SPATIAL1"})


def test_coordinate_frame_api():
forward = m.Linear1D(slope=0.1*u.deg/u.pix, intercept=0*u.deg)

output_frame = cf.CoordinateFrame(1, "SPATIAL", (0,), unit=(u.deg,), name="sepframe")
input_frame = cf.CoordinateFrame(1, "PIXEL", (0,), unit=(u.pix,))

wcs = gwcs.WCS(forward_transform=forward, input_frame=input_frame, output_frame=output_frame)

world = wcs.pixel_to_world(0)
assert isinstance(world, u.Quantity)

pixel = wcs.world_to_pixel(world)
assert isinstance(pixel, float)

pixel2 = wcs.invert(world)
assert u.allclose(pixel2, 0*u.pix)
3 changes: 2 additions & 1 deletion gwcs/tests/test_api_slicing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import astropy.units as u
from astropy.coordinates import Galactic, SkyCoord, SpectralCoord
from astropy.wcs.wcsapi.sliced_low_level_wcs import SlicedLowLevelWCS
from astropy.wcs.wcsapi.wrappers import SlicedLowLevelWCS
from numpy.testing import assert_allclose, assert_equal

EXPECTED_ELLIPSIS_REPR = """
Expand Down
4 changes: 3 additions & 1 deletion gwcs/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ def test_fits_transform():
def test_lon_pole():
tan = models.Pix2Sky_TAN()
car = models.Pix2Sky_CAR()
azp = models.Pix2Sky_AZP(mu=-1.35, gamma=25.8458)
sky_positive_lat = coord.SkyCoord(3 * u.deg, 1 * u.deg)
sky_negative_lat = coord.SkyCoord(3 * u.deg, -1 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole(sky_positive_lat, tan), 180 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole(sky_negative_lat, tan), 180 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole(sky_positive_lat, car), 0 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole(sky_negative_lat, car), 180 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole((0, 34 * u.rad), tan), 180 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole((0, 0.34 * u.rad), tan), 180 * u.deg)
assert_quantity_allclose(gwutils._compute_lon_pole((1 * u.rad, 0.34 * u.rad), azp), 180 * u.deg)
assert_allclose(gwutils._compute_lon_pole((1, -34), tan), 180)


Expand Down
74 changes: 51 additions & 23 deletions gwcs/tests/test_wcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
spec = cf.SpectralFrame(name='wave', unit=[u.m, ], axes_order=(2, ), axes_names=('lambda', ))
time = cf.TemporalFrame(name='time', unit=[u.s, ], axes_order=(3, ), axes_names=('time', ), reference_frame=Time("2020-01-01"))

pipe = [(detector, m1),
(focal, m2),
(icrs, None)
pipe = [wcs.Step(detector, m1),
wcs.Step(focal, m2),
wcs.Step(icrs, None)
]

# Create some data.
Expand Down Expand Up @@ -75,15 +75,19 @@ def test_init_no_transform():
gw = wcs.WCS(output_frame='icrs')
assert len(gw._pipeline) == 2
assert gw.pipeline[0].frame == "detector"
assert gw.pipeline[0][0] == "detector"
with pytest.warns(DeprecationWarning, match="Indexing a WCS.pipeline step is deprecated."):
assert gw.pipeline[0][0] == "detector"
assert gw.pipeline[1].frame == "icrs"
assert gw.pipeline[1][0] == "icrs"
with pytest.warns(DeprecationWarning, match="Indexing a WCS.pipeline step is deprecated."):
assert gw.pipeline[1][0] == "icrs"
assert np.in1d(gw.available_frames, ['detector', 'icrs']).all()
gw = wcs.WCS(output_frame=icrs, input_frame=detector)
assert gw._pipeline[0].frame == "detector"
assert gw._pipeline[0][0] == "detector"
with pytest.warns(DeprecationWarning, match="Indexing a WCS.pipeline step is deprecated."):
assert gw._pipeline[0][0] == "detector"
assert gw._pipeline[1].frame == "icrs"
assert gw._pipeline[1][0] == "icrs"
with pytest.warns(DeprecationWarning, match="Indexing a WCS.pipeline step is deprecated."):
assert gw._pipeline[1][0] == "icrs"
assert np.in1d(gw.available_frames, ['detector', 'icrs']).all()
with pytest.raises(NotImplementedError):
gw(1, 2)
Expand Down Expand Up @@ -154,7 +158,7 @@ def test_get_transform():
x, y = 1, 2
fx, fy = tr_forward(1, 2)
assert_allclose(w.pipeline[0].transform(x, y), (fx, fy))
assert_allclose(w.pipeline[0][1](x, y), (fx, fy))
assert_allclose(w.pipeline[0].transform(x, y), (fx, fy))
assert_allclose((x, y), tr_back(*w(x, y)))
assert(w.get_transform('detector', 'detector') is None)

Expand Down Expand Up @@ -368,9 +372,14 @@ def test_grid_from_bounding_box_step():
def test_wcs_from_points():
np.random.seed(0)
hdr = fits.Header.fromtextfile(get_pkg_data_filename("data/acs.hdr"), endcard=False)
with warnings.catch_warnings() as w:
warnings.simplefilter("ignore")
with pytest.warns(astwcs.FITSFixedWarning) as caught_warnings:
# this raises a warning unimportant for this testing the pix2world
# FITSFixedWarning(u'The WCS transformation has more axes (2) than
# the image it is associated with (0)')
# FITSFixedWarning: 'datfix' made the change
# 'Set MJD-OBS to 53436.000000 from DATE-OBS'. [astropy.wcs.wcs]
w = astwcs.WCS(hdr)
assert len(caught_warnings) == 2
y, x = np.mgrid[:2046:20j, :4023:10j]
ra, dec = w.wcs_pix2world(x, y, 1)
fiducial = coord.SkyCoord(ra.mean()*u.deg, dec.mean()*u.deg, frame="icrs")
Expand Down Expand Up @@ -517,7 +526,14 @@ def test_high_level_api():
class TestImaging(object):
def setup_class(self):
hdr = fits.Header.fromtextfile(get_pkg_data_filename("data/acs.hdr"), endcard=False)
self.fitsw = astwcs.WCS(hdr)
with pytest.warns(astwcs.FITSFixedWarning) as caught_warnings:
# this raises a warning unimportant for this testing the pix2world
# FITSFixedWarning(u'The WCS transformation has more axes (2) than
# the image it is associated with (0)')
# FITSFixedWarning: 'datfix' made the change
# 'Set MJD-OBS to 53436.000000 from DATE-OBS'. [astropy.wcs.wcs]
self.fitsw = astwcs.WCS(hdr)
assert len(caught_warnings) == 2
a_coeff = hdr['A_*']
a_order = a_coeff.pop('A_ORDER')
b_coeff = hdr['B_*']
Expand All @@ -544,9 +560,9 @@ def setup_class(self):
sky_cs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky')
det = cf.Frame2D(name='detector')
wcs_forward = wcslin | tan | n2c
pipeline = [('detector', distortion),
('focal', wcs_forward),
(sky_cs, None)
pipeline = [wcs.Step('detector', distortion),
wcs.Step('focal', wcs_forward),
wcs.Step(sky_cs, None)
]

self.wcs = wcs.WCS(input_frame=det,
Expand All @@ -555,7 +571,6 @@ def setup_class(self):

self.xv, self.yv = xv, yv

@pytest.mark.filterwarnings('ignore')
def test_distortion(self):
sipx, sipy = self.fitsw.sip_pix2foc(self.xv, self.yv, 1)
sipx = np.array(sipx) + 2048
Expand Down Expand Up @@ -759,7 +774,11 @@ def test_to_fits_sip_composite_frame_keep_axis(gwcs_cube_with_separable_spectral
assert fw_hdr[f'CTYPE{ra_axis}'] == 'RA---TAN'
assert fw_hdr['WCSAXES'] == 2

fw = astwcs.WCS(fw_hdr)
with pytest.warns(astwcs.FITSFixedWarning, match='The WCS transformation has more axes'):
# this raises a warning unimportant for this testing the pix2world
# FITSFixedWarning(u'The WCS transformation has more axes (3) than
# the image it is associated with (2)')
fw = astwcs.WCS(fw_hdr)
gskyval = w(1, 45, 55)[1:]
assert np.allclose(gskyval, fw.all_pix2world([[1, 45, 55]], 0)[0][1:])

Expand Down Expand Up @@ -805,8 +824,7 @@ def test_to_fits_tab_cube(gwcs_3d_galactic_spectral):
assert np.allclose(w(x, y, z), fits_wcs_user_bb.wcs_pix2world(x, y, z, 0),
rtol=1e-6, atol=1e-7)


@pytest.mark.skip(reason="Fails round-trip for -TAB axis 5")
@pytest.mark.filterwarnings('ignore:.*The WCS transformation has more axes.*')
def test_to_fits_tab_7d(gwcs_7d_complex_mapping):
# gWCS:
w = gwcs_7d_complex_mapping
Expand Down Expand Up @@ -874,7 +892,11 @@ def test_to_fits_no_sip_used(gwcs_spec_cel_time_4d):
w = gwcs_spec_cel_time_4d

# create FITS headers and -TAB headers
hdr, _ = w.to_fits(degree=3)
with pytest.warns(UserWarning, match='SIP distortion is not supported when the number'):
# UserWarning: SIP distortion is not supported when the number
# of axes in WCS is larger than 2. Setting 'degree'
# to 1 and 'max_inv_pix_error' to None.
hdr, _ = w.to_fits(degree=3)

# check that FITS WCS is not using SIP
assert not hdr['?_ORDER']
Expand Down Expand Up @@ -982,6 +1004,7 @@ def test_to_fits_tab_miri_image():
hdulist = fits.HDUList(
[fits.PrimaryHDU(np.ones(w.pixel_n_dim * (2, )), hdr), bt]
)

fits_wcs = astwcs.WCS(hdulist[0].header, hdulist)

# test points:
Expand All @@ -1004,7 +1027,11 @@ def test_to_fits_tab_miri_lrs():
hdulist = fits.HDUList(
[fits.PrimaryHDU(np.ones(w.pixel_n_dim * (2, )), hdr), bt[0]]
)
fits_wcs = astwcs.WCS(hdulist[0].header, hdulist)
with pytest.warns(astwcs.FITSFixedWarning, match='The WCS transformation has more axes'):
# this raises a warning unimportant for this testing the pix2world
# FITSFixedWarning(u'The WCS transformation has more axes (3) than
# the image it is associated with (2)')
fits_wcs = astwcs.WCS(hdulist[0].header, hdulist)

# test points:
(xmin, xmax), (ymin, ymax) = w.bounding_box
Expand Down Expand Up @@ -1181,12 +1208,11 @@ def test_tabular_2d_quantity():
assert all(u.allclose(u.Quantity(b), [0, 2] * u.pix) for b in bb)


@pytest.mark.filterwarnings("error:.*Indexing a WCS.pipeline step is deprecated.*:DeprecationWarning")
def test_initialize_wcs_with_list():
# test that you can initialize a wcs with a pipeline that is a list
# containing both Step() and (frame, transform) tuples

# make pipline consisting of tuples and Steps
# make pipeline consisting of tuples and Steps
shift1 = models.Shift(10 * u .pix) & models.Shift(2 * u.pix)
shift2 = models.Shift(3 * u.pix)
pipeline = [('detector', shift1), wcs.Step('extra_step', shift2)]
Expand All @@ -1195,4 +1221,6 @@ def test_initialize_wcs_with_list():
pipeline.append(extra_step)

# make sure no warnings occur when creating wcs with this pipeline
wcs.WCS(pipeline)
with warnings.catch_warnings():
warnings.simplefilter("error")
wcs.WCS(pipeline)
Loading

0 comments on commit e8209c0

Please sign in to comment.