def time_init_7_no_units(): m = (models.Shift(-10.5) & models.Shift(-13.2) | models.AffineTransformation2D(matrix=[[1, 0], [0, 1]], translation=[0, 0]) | models.Scale(.01) & models.Scale(.04) | models.Pix2Sky_TAN() | models.RotateNative2Celestial(5.6, -72.05, 180))
def test_from_fiducial_composite(): sky = coord.SkyCoord(1.63 * u.radian, -72.4 * u.deg, frame='fk5') tan = models.Pix2Sky_TAN() spec = cf.SpectralFrame(unit=(u.micron, ), axes_order=(0, )) celestial = cf.CelestialFrame(reference_frame=sky.frame, unit=(sky.spherical.lon.unit, sky.spherical.lat.unit), axes_order=(1, 2)) coord_frame = cf.CompositeFrame([spec, celestial], name='cube_frame') w = wcs_from_fiducial([.5, sky], coord_frame, projection=tan) assert isinstance(w.cube_frame.frames[1].reference_frame, coord.FK5) assert_allclose(w(1, 1, 1), (1.5, 96.52373368309931, -71.37420187296995)) # test returning coordinate objects with composite output_frame res = w(1, 2, 2, with_units=True) assert_allclose(res[0], u.Quantity(1.5 * u.micron)) assert isinstance(res[1], coord.SkyCoord) assert_allclose(res[1].ra.value, 99.329496642319) assert_allclose(res[1].dec.value, -70.30322020351122) trans = models.Shift(10) & models.Scale(2) & models.Shift(-1) w = wcs_from_fiducial([.5, sky], coord_frame, projection=tan, transform=trans) assert_allclose(w(1, 1, 1), (11.5, 99.97738475762152, -72.29039139739766)) # test coordinate object output coord_result = w(1, 1, 1, with_units=True) assert_allclose(coord_result[0], u.Quantity(11.5 * u.micron))
def setup(self): aff = models.AffineTransformation2D(matrix=[[1, 0], [0, 1]], translation=[0, 0]) self.model = (models.Shift(-10.5) & models.Shift(-13.2) | aff | models.Scale(.01) & models.Scale(.04) | models.Pix2Sky_TAN() | models.RotateNative2Celestial(5.6, -72.05, 180))
def test_simple_gwcs(): # https://gwcs.readthedocs.io/en/latest/#getting-started shift_by_crpix = models.Shift(-(2048 - 1) * u.pix) & models.Shift(-(1024 - 1) * u.pix) matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06], [5.0226382102765E-06, -1.2644844123757E-05]]) rotation = models.AffineTransformation2D(matrix * u.deg, translation=[0, 0] * u.deg) rotation.input_units_equivalencies = {"x": u.pixel_scale(1 * (u.deg / u.pix)), "y": u.pixel_scale(1 * (u.deg / u.pix))} rotation.inverse = models.AffineTransformation2D(np.linalg.inv(matrix) * u.pix, translation=[0, 0] * u.pix) rotation.inverse.input_units_equivalencies = {"x": u.pixel_scale(1 * (u.pix / u.deg)), "y": u.pixel_scale(1 * (u.pix / u.deg))} tan = models.Pix2Sky_TAN() celestial_rotation = models.RotateNative2Celestial( 5.63056810618 * u.deg, -72.05457184279 * u.deg, 180 * u.deg) det2sky = shift_by_crpix | rotation | tan | celestial_rotation det2sky.name = "linear_transform" detector_frame = cf.Frame2D(name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix)) sky_frame = cf.CelestialFrame(reference_frame=ICRS(), name='icrs', unit=(u.deg, u.deg)) pipeline = [(detector_frame, det2sky), (sky_frame, None)] w = gwcs.wcs.WCS(pipeline) result = wcs_utils.get_compass_info(w, (1024, 2048), r_fac=0.25) assert_allclose(result[:-1], (1024.0, 512.0, 1131.0265005852038, 279.446189124443, 1262.0057201165127, 606.2863901330095, 155.2870478938214, -86.89813081941797)) assert not result[-1]
def gwcs_simple_imaging_units(): shift_by_crpix = models.Shift(-2048 * u.pix) & models.Shift(-1024 * u.pix) matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06], [5.0226382102765E-06, -1.2644844123757E-05]]) rotation = models.AffineTransformation2D(matrix * u.deg, translation=[0, 0] * u.deg) rotation.input_units_equivalencies = { "x": u.pixel_scale(1 * u.deg / u.pix), "y": u.pixel_scale(1 * u.deg / u.pix) } rotation.inverse = models.AffineTransformation2D( np.linalg.inv(matrix) * u.pix, translation=[0, 0] * u.pix) rotation.inverse.input_units_equivalencies = { "x": u.pixel_scale(1 * u.pix / u.deg), "y": u.pixel_scale(1 * u.pix / u.deg) } tan = models.Pix2Sky_TAN() celestial_rotation = models.RotateNative2Celestial(5.63056810618 * u.deg, -72.05457184279 * u.deg, 180 * u.deg) det2sky = shift_by_crpix | rotation | tan | celestial_rotation det2sky.name = "linear_transform" detector_frame = cf.Frame2D(name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix)) sky_frame = cf.CelestialFrame(reference_frame=coord.ICRS(), name='icrs', unit=(u.deg, u.deg)) pipeline = [(detector_frame, det2sky), (sky_frame, None)] return wcs.WCS(pipeline)
def generate_s3d_wcs(): """ create a fake gwcs for a cube """ # create input /output frames detector = cf.CoordinateFrame(name='detector', axes_order=(0,1,2), axes_names=['x', 'y', 'z'], axes_type=['spatial', 'spatial', 'spatial'], naxes=3, unit=['pix', 'pix', 'pix']) sky = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_names=("RA", "DEC")) spec = cf.SpectralFrame(name='spectral', unit=['um'], axes_names=['wavelength'], axes_order=(2,)) world = cf.CompositeFrame(name="world", frames=[sky, spec]) # create fake transform to at least get a bounding box # for the s3d jwst loader # shape 30,10,10 (spec, y, x) crpix1, crpix2, crpix3 = 5, 5, 15 # (x, y, spec) crval1, crval2, crval3 = 1, 1, 1 cdelt1, cdelt2, cdelt3 = 0.01, 0.01, 0.05 shift = models.Shift(-crpix2) & models.Shift(-crpix1) scale = models.Multiply(cdelt2) & models.Multiply(cdelt1) proj = models.Pix2Sky_TAN() skyrot = models.RotateNative2Celestial(crval2, 90 + crval1, 180) celestial = shift | scale | proj | skyrot wave_model = models.Shift(-crpix3) | models.Multiply(cdelt3) | models.Shift(crval3) transform = models.Mapping((2, 0, 1)) | celestial & wave_model | models.Mapping((1, 2, 0)) # bounding box based on shape (30,10,10) in test transform.bounding_box = ((0, 29), (0, 9), (0, 9)) # create final wcs pipeline = [(detector, transform), (world, None)] return WCS(pipeline)
def test1(tmpdir, ret=False): shift_by_crpix = models.Shift(-2048 * u.pix) & models.Shift(-1024 * u.pix) matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06], [5.0226382102765E-06, -1.2644844123757E-05]]) rotation = models.AffineTransformation2D(matrix * u.deg, translation=[0, 0] * u.deg) rotation.input_units_equivalencies = { "x": u.pixel_scale(1 * u.deg / u.pix), "y": u.pixel_scale(1 * u.deg / u.pix) } rotation.inverse = models.AffineTransformation2D( np.linalg.inv(matrix) * u.pix, translation=[0, 0] * u.pix) rotation.inverse.input_units_equivalencies = { "x": u.pixel_scale(1 * u.pix / u.deg), "y": u.pixel_scale(1 * u.pix / u.deg) } tan = models.Pix2Sky_TAN() celestial_rotation = models.RotateNative2Celestial(5.63056810618 * u.deg, -72.05457184279 * u.deg, 180 * u.deg) det2sky = shift_by_crpix | rotation | tan | celestial_rotation det2sky.name = "linear_transform" detector_frame = cf.Frame2D(name="detector", axes_names=("x", "y"), unit=(u.pix, u.pix)) sky_frame = cf.CelestialFrame(reference_frame=coords.ICRS(), name='icrs', unit=(u.deg, u.deg)) pipeline = [(detector_frame, det2sky), (sky_frame, None)] wcsobj = gwcs.wcs.WCS(pipeline) wcs_set = WcsSet(default=wcsobj, extra=wcsobj) tree = {'wcs_set': wcs_set} if ret: return wcs_set helpers.assert_roundtrip_tree(tree, tmpdir)
def generate_celestial_transform(crpix: Union[Iterable[float], u.Quantity], cdelt: Union[Iterable[float], u.Quantity], pc: Union[ArrayLike, u.Quantity], crval: Union[Iterable[float], u.Quantity], lon_pole: Union[float, u.Quantity] = None, projection: Model = m.Pix2Sky_TAN()) -> CompoundModel: """ Create a simple celestial transform from FITS like parameters. Supports unitful or unitless parameters, but if any parameters have units all must have units, if parameters are unitless they are assumed to be in degrees. Parameters ---------- crpix The reference pixel (a length two array). crval The world coordinate at the reference pixel (a length two array). pc The rotation matrix for the affine transform. If specifying parameters with units this should have celestial (``u.deg``) units. lon_pole The longitude of the celestial pole, defaults to 180 degrees. projection The map projection to use, defaults to ``TAN``. Notes ----- This function has not been tested with more complex projections. Ensure that your lon_pole is correct for your projection. """ spatial_unit = None if hasattr(crval[0], "unit"): spatial_unit = crval[0].unit # TODO: Note this assumption is only valid for certain projections. if lon_pole is None: lon_pole = 180 if spatial_unit is not None: lon_pole = u.Quantity(lon_pole, unit=spatial_unit) # Make translation unitful if all parameters have units translation = (0, 0) if spatial_unit is not None: translation *= pc.unit # If we have units then we need to convert all things to Quantity # as they might be Parameter classes crpix = u.Quantity(crpix) cdelt = u.Quantity(cdelt) crval = u.Quantity(crval) lon_pole = u.Quantity(lon_pole) pc = u.Quantity(pc) shift = m.Shift(-crpix[0]) & m.Shift(-crpix[1]) scale = m.Multiply(cdelt[0]) & m.Multiply(cdelt[1]) rot = m.AffineTransformation2D(pc, translation=translation) skyrot = m.RotateNative2Celestial(crval[0], crval[1], lon_pole) return shift | scale | rot | projection | skyrot
def test_fix_inputs(tmpdir): model = astmodels.Pix2Sky_TAN() | astmodels.Rotation2D() tree = { 'compound': fix_inputs(model, {'x': 45}), 'compound1': fix_inputs(model, {0: 45}) } helpers.assert_roundtrip_tree(tree, tmpdir)
def test_fix_inputs_type(): with pytest.raises(TypeError): tree = {'compound': fix_inputs(3, {'x': 45})} helpers.assert_roundtrip_tree(tree, tmpdir) with pytest.raises(AttributeError): tree = {'compound': astmodels.Pix2Sky_TAN() & {'x': 45}} helpers.assert_roundtrip_tree(tree, tmpdir)
def gwcs_7d_complex_mapping(): """ Useful features of this WCS (axes indices here are 0-based): - includes two celestial axes: input (0, 1) maps to world (2 - RA, 1 - Dec) - includes one separable frame with one axis: 4 -> 2 - includes one frame with 3 input and 4 output axes (1 degenerate), with separable world axes (3, 5) and (0, 6). """ offx = models.Shift(-64, name='x_translation') offy = models.Shift(-32, name='y_translation') cd = np.array([[1.2906, 0.59532], [0.50222, -1.2645]]) aff = models.AffineTransformation2D(matrix=1e-5 * cd, name='rotation') aff2 = models.AffineTransformation2D(matrix=cd, name='rotation2') wcslin = (offx & offy) | aff tan = models.Pix2Sky_TAN(name='tangent_projection') n2c = models.RotateNative2Celestial(5.630568, -72.0546, 180, name='skyrot') icrs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_order=(2, 1)) spec = cf.SpectralFrame(name='wave', unit=[u.m], axes_order=(4, ), axes_names=('lambda', )) cmplx = cf.CoordinateFrame( name="complex", naxes=4, axes_order=(3, 5, 0, 6), axis_physical_types=(['em.wl', 'em.wl', 'time', 'time']), axes_type=("SPATIAL", "SPATIAL", "TIME", "TIME"), axes_names=("x", "y", "t", 'tau'), unit=(u.m, u.m, u.second, u.second)) comp_frm = cf.CompositeFrame(frames=[icrs, spec, cmplx], name='TEST 7D') wcs_forward = ( (wcslin & models.Shift(-3.14) & models.Scale(2.7) & aff2) | (tan & models.Identity(1) & models.Identity(1) & models.Identity(2)) | (n2c & models.Identity(1) & models.Identity(1) & models.Identity(2)) | models.Mapping((3, 1, 0, 4, 2, 5, 3))) detector_frame = cf.CoordinateFrame(name="detector", naxes=6, axes_order=(0, 1, 2, 3, 4, 5), axes_type=("pixel", "pixel", "pixel", "pixel", "pixel", "pixel"), unit=(u.pix, u.pix, u.pix, u.pix, u.pix, u.pix)) pipeline = [('detector', wcs_forward), (comp_frm, None)] w = wcs.WCS(forward_transform=wcs_forward, output_frame=comp_frm, input_frame=detector_frame) w.bounding_box = ((0, 15), (0, 31), (0, 20), (0, 10), (0, 10), (0, 1)) w.array_shape = (2, 11, 11, 21, 32, 16) w.pixel_shape = (16, 32, 21, 11, 11, 2) return w
def deproject_from_tangent_plane(x, y, ra_ref, dec_ref, scale=1., unwrap=True): """Convert pixel coordinates into ra/dec coordinates using a tangent plane de-projection. The projection's reference point has to be specified. See the inverse transformation radec2Pix_TAN. Parameters ---------- x : float or array of floats Pixel coordinate (default is in decimal degrees, but depends on value of scale parameter) x/scale has to be degrees. y : float or array of floats Pixel coordinate (default is in decimal degrees, but depends on value of scale parameter) x/scale has to be degrees. ra_ref : float Right Ascension of reference point in decimal degrees dec_ref: float declination of reference point in decimal degrees scale : float Multiplicative factor that is applied to the input values. Default is 1.0 Returns ------- ra : float Right Ascension in decimal degrees dec: float declination in decimal degrees """ # for zenithal projections, i.e. gnomonic, i.e. TAN if isinstance(ra_ref, u.Quantity): lonpole = 180. * u.deg else: lonpole = 180. x = x / scale y = y / scale # tangent plane projection from x,y to phi/theta tan = astmodels.Pix2Sky_TAN() # compute native coordinate rotation to obtain ra and dec rot_for_tan = astrotations.RotateNative2Celestial(ra_ref, dec_ref, lonpole) phi, theta = tan(x, y) # ra and dec ra, dec = rot_for_tan(phi, theta) if unwrap: if (np.ndim(ra) == 0): if (ra > 180.): ra -= 360. else: ra[ra > 180.] -= 360. return ra, dec
def setup(self): aff = models.AffineTransformation2D(matrix=[[1, 0], [0, 1]] * u.arcsec, translation=[0, 0] * u.arcsec) aff.input_units_equivalencies = {'x': u.pixel_scale(1 * u.arcsec/u.pix), 'y': u.pixel_scale(1 * u.arcsec/u.pix)} self.model = (models.Shift(-10.5 * u.pix) & models.Shift(-13.2 * u.pix) | aff | models.Scale(.01 * u.arcsec) & models.Scale(.04 * u.deg) | models.Pix2Sky_TAN() | models.RotateNative2Celestial(5.6 * u.deg, -72.05 * u.deg, 180 * u.deg))
def test_to_fits_sip_pc_normalization(gwcs_simple_imaging_units, matrix_type): y, x = np.mgrid[:1024:10, :1024:10] xflat = np.ravel(x[1:-1, 1:-1]) yflat = np.ravel(y[1:-1, 1:-1]) bounding_box = ((0, 1024), (0, 1024)) # create a simple imaging WCS without distortions: cdmat = np.array([[1.29e-5, 5.95e-6], [5.02e-6, -1.26e-5]]) aff = models.AffineTransformation2D(matrix=cdmat, name='rotation') offx = models.Shift(-501, name='x_translation') offy = models.Shift(-501, name='y_translation') wcslin = (offx & offy) | aff n2c = models.RotateNative2Celestial(5.63, -72.05, 180, name='sky_rotation') tan = models.Pix2Sky_TAN(name='tangent_projection') wcs_forward = wcslin | tan | n2c sky_cs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky') pipeline = [('detector', wcs_forward), (sky_cs, None)] wcs_lin = wcs.WCS( input_frame=cf.Frame2D(name='detector'), output_frame=sky_cs, forward_transform=pipeline ) _, _, celestial_group = wcs_lin._separable_groups(detect_celestial=True) fits_wcs = wcs_lin._to_fits_sip( celestial_group=celestial_group, keep_axis_position=False, bounding_box=bounding_box, max_pix_error=0.1, degree=None, max_inv_pix_error=0.1, inv_degree=None, npoints=32, crpix=None, projection='TAN', matrix_type=matrix_type, verbose=False ) fitssip = astwcs.WCS(fits_wcs) fitsvalx, fitsvaly = fitssip.wcs_pix2world(xflat, yflat, 0) inv_fitsvalx, inv_fitsvaly = fitssip.wcs_world2pix(fitsvalx, fitsvaly, 0) gwcsvalx, gwcsvaly = wcs_lin(xflat, yflat) assert_allclose(gwcsvalx, fitsvalx, atol=4e-11, rtol=0) assert_allclose(gwcsvaly, fitsvaly, atol=4e-11, rtol=0) assert_allclose(xflat, inv_fitsvalx, atol=5e-9, rtol=0) assert_allclose(yflat, inv_fitsvaly, atol=5e-9, rtol=0)
def gwcs_spec_cel_time_4d(): """ A complex 4D mixed celestial + spectral + time WCS. """ # spectroscopic frame: wave_model = models.Shift(-5) | models.Multiply(3.7) | models.Shift(20) wave_model.bounding_box = (7, 50) wave_frame = cf.SpectralFrame(name='wave', unit=u.m, axes_order=(0, ), axes_names=('lambda', )) # time frame: time_model = models.Identity(1) # models.Linear1D(10, 0) time_frame = cf.TemporalFrame(Time("2010-01-01T00:00"), name='time', unit=u.s, axes_order=(3, )) # Values from data/acs.hdr: crpix = (12, 13) crval = (5.63, -72.05) cd = [[1.291E-05, 5.9532E-06], [5.02215E-06, -1.2645E-05]] aff = models.AffineTransformation2D(matrix=cd, name='rotation') offx = models.Shift(-crpix[0], name='x_translation') offy = models.Shift(-crpix[1], name='y_translation') wcslin = models.Mapping((1, 0)) | (offx & offy) | aff tan = models.Pix2Sky_TAN(name='tangent_projection') n2c = models.RotateNative2Celestial(*crval, 180, name='sky_rotation') cel_model = wcslin | tan | n2c icrs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_order=(2, 1)) wcs_forward = wave_model & cel_model & time_model comp_frm = cf.CompositeFrame(frames=[wave_frame, icrs, time_frame], name='TEST 4D FRAME') detector_frame = cf.CoordinateFrame(name="detector", naxes=4, axes_order=(0, 1, 2, 3), axes_type=("pixel", "pixel", "pixel", "pixel"), unit=(u.pix, u.pix, u.pix, u.pix)) w = wcs.WCS(forward_transform=wcs_forward, output_frame=comp_frm, input_frame=detector_frame) w.bounding_box = ((0, 63), (0, 127), (0, 255), (0, 9)) w.array_shape = (10, 256, 128, 64) w.pixel_shape = (64, 128, 256, 10) return w
def __init__(self, *args, crval_table=None, pc_table=None, projection=m.Pix2Sky_TAN(), **kwargs): super().__init__(*args, **kwargs) (self.table_shape, self.pc_table, self.crval_table) = self._validate_table_shapes(np.asanyarray(pc_table), np.asanyarray(crval_table)) if not isinstance(projection, m.Pix2SkyProjection): raise TypeError("The projection keyword should be a Pix2SkyProjection model class.") self.projection = projection
def gwcs_cube_with_separable_time(request): """ A mixed celestial + time WCS. """ cube_size = (64, 32, 128) axes_order = request.param time_axes_order = (axes_order.index(2), ) cel_axes_order = (axes_order.index(0), axes_order.index(1)) detector_frame = cf.CoordinateFrame(name="detector", naxes=3, axes_order=(0, 1, 2), axes_type=("pixel", "pixel", "pixel"), unit=(u.pix, u.pix, u.pix)) # time frame: time_model = models.Identity(1) # models.Linear1D(10, 0) time_frame = cf.TemporalFrame(Time("2010-01-01T00:00"), name='time', unit=u.s, axes_order=time_axes_order) # Values from data/acs.hdr: crpix = (12, 13) crval = (5.63, -72.05) cd = [[1.291E-05, 5.9532E-06], [5.02215E-06, -1.2645E-05]] aff = models.AffineTransformation2D(matrix=cd, name='rotation') offx = models.Shift(-crpix[0], name='x_translation') offy = models.Shift(-crpix[1], name='y_translation') wcslin = models.Mapping((1, 0)) | (offx & offy) | aff tan = models.Pix2Sky_TAN(name='tangent_projection') n2c = models.RotateNative2Celestial(*crval, 180, name='sky_rotation') cel_model = wcslin | tan | n2c icrs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_order=cel_axes_order) wcs_forward = (cel_model & time_model) | models.Mapping(axes_order) comp_frm = cf.CompositeFrame(frames=[icrs, time_frame], name='TEST 3D FRAME WITH TIME') w = wcs.WCS(forward_transform=wcs_forward, output_frame=comp_frm, input_frame=detector_frame) w.bounding_box = tuple((0, k - 1) for k in cube_size) w.pixel_shape = cube_size w.array_shape = w.pixel_shape[::-1] return w
def test_fix_inputs(tmpdir): with warnings.catch_warnings(): # Some schema files are missing from asdf<=2.4.2 which causes warnings if LooseVersion(asdf.__version__) <= '2.4.2': warnings.filterwarnings('ignore', 'Unable to locate schema file') model = astmodels.Pix2Sky_TAN() | astmodels.Rotation2D() tree = { 'compound': fix_inputs(model, {'x': 45}), 'compound1': fix_inputs(model, {0: 45}) } helpers.assert_roundtrip_tree(tree, tmpdir)
def gwcs_cube_with_separable_spectral(request): cube_size = (128, 64, 100) axes_order = request.param spectral_axes_order = (axes_order.index(2), ) cel_axes_order = (axes_order.index(0), axes_order.index(1)) # Values from data/acs.hdr: crpix = (64, 32) crval = (5.63056810618, -72.0545718428) cd = [[1.29058667557984E-05, 5.95320245884555E-06], [5.02215195623825E-06, -1.2645010396976E-05]] aff = models.AffineTransformation2D(matrix=cd, name='rotation') offx = models.Shift(-crpix[0], name='x_translation') offy = models.Shift(-crpix[1], name='y_translation') wcslin = (offx & offy) | aff tan = models.Pix2Sky_TAN(name='tangent_projection') n2c = models.RotateNative2Celestial(*crval, 180, name='sky_rotation') icrs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky', axes_order=cel_axes_order) spec = cf.SpectralFrame(name='wave', unit=[ u.m, ], axes_order=spectral_axes_order, axes_names=('lambda', )) comp_frm = cf.CompositeFrame(frames=[icrs, spec], name='TEST 3D FRAME WITH SPECTRAL AXIS') wcs_forward = ((wcslin & models.Identity(1)) | (tan & models.Identity(1)) | (n2c & models.Identity(1)) | models.Mapping(axes_order)) detector_frame = cf.CoordinateFrame(name="detector", naxes=3, axes_order=(0, 1, 2), axes_type=("pixel", "pixel", "pixel"), unit=(u.pix, u.pix, u.pix)) w = wcs.WCS(forward_transform=wcs_forward, output_frame=comp_frm, input_frame=detector_frame) w.bounding_box = tuple((0, k - 1) for k in cube_size) w.pixel_shape = cube_size w.array_shape = w.pixel_shape[::-1] return w, axes_order
def test_lon_pole(): tan = models.Pix2Sky_TAN() car = models.Pix2Sky_CAR() 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_allclose(gwutils._compute_lon_pole((1, -34), tan), 180)
def setup_class(self): hdr = fits.Header.fromtextfile(get_pkg_data_filename("data/acs.hdr"), endcard=False) #warnings.filterwarnings("ignore", message="^The WCS transformation has more axes (2)", # module="astropy.wcs.wcs") self.fitsw = astwcs.WCS(hdr) a_coeff = hdr['A_*'] a_order = a_coeff.pop('A_ORDER') b_coeff = hdr['B_*'] b_order = b_coeff.pop('B_ORDER') crpix = [hdr['CRPIX1'], hdr['CRPIX2']] distortion = models.SIP( crpix, a_order, b_order, a_coeff, b_coeff, name='sip_distorion') + models.Identity(2) cdmat = np.array([[hdr['CD1_1'], hdr['CD1_2']], [hdr['CD2_1'], hdr['CD2_2']]]) aff = models.AffineTransformation2D(matrix=cdmat, name='rotation') offx = models.Shift(-hdr['CRPIX1'], name='x_translation') offy = models.Shift(-hdr['CRPIX2'], name='y_translation') wcslin = (offx & offy) | aff phi = hdr['CRVAL1'] lon = hdr['CRVAL2'] theta = 180 n2c = models.RotateNative2Celestial(phi, lon, theta, name='sky_rotation') tan = models.Pix2Sky_TAN(name='tangent_projection') sky_cs = cf.CelestialFrame(reference_frame=coord.ICRS(), name='sky') det = cf.Frame2D('detector') wcs_forward = wcslin | tan | n2c pipeline = [('detector', distortion), ('focal', wcs_forward), (sky_cs, None)] self.wcs = wcs.WCS(input_frame=det, output_frame=sky_cs, forward_transform=pipeline) nx, ny = (5, 2) x = np.linspace(0, 1, nx) y = np.linspace(0, 1, ny) self.xv, self.yv = np.meshgrid(x, y)
def test_from_fiducial_composite(): sky = coord.SkyCoord(1.63 * u.radian, -72.4 * u.deg, frame='fk5') tan = models.Pix2Sky_TAN() spec = cf.SpectralFrame(unit=(u.micron, )) celestial = cf.CelestialFrame(reference_frame=sky.frame, unit=(sky.spherical.lon.unit, sky.spherical.lat.unit)) coord_frame = cf.CompositeFrame([spec, celestial], name='cube_frame') w = wcs_from_fiducial([.5 * u.micron, sky], coord_frame, projection=tan) assert isinstance(w.cube_frame.frames[1].reference_frame, coord.FK5) assert_allclose(w(1, 1, 1), (1.5, 96.52373368309931, -71.37420187296995)) trans = models.Shift(10) & models.Scale(2) & models.Shift(-1) w = wcs_from_fiducial([.5 * u.micron, sky], coord_frame, projection=tan, transform=trans) assert_allclose(w(1, 1, 1), (11.5, 99.97738475762152, -72.29039139739766))
def test_against_wcslib(inp): w = wcs.WCS() crval = [202.4823228, 47.17511893] w.wcs.crval = crval w.wcs.ctype = ['RA---TAN', 'DEC--TAN'] lonpole = 180 tan = models.Pix2Sky_TAN() n2c = models.RotateNative2Celestial(crval[0], crval[1], lonpole) c2n = models.RotateCelestial2Native(crval[0], crval[1], lonpole) m = tan | n2c minv = c2n | tan.inverse radec = w.wcs_pix2world(inp[0], inp[1], 1) xy = w.wcs_world2pix(radec[0], radec[1], 1) assert_allclose(m(*inp), radec, atol=1e-12) assert_allclose(minv(*radec), xy, atol=1e-12)
def create_asdf_ref_files(fname): #f = fits.open('../j94f05bgq_flt.fits') f = fits.open(fname) from gwcs import util whdr = util.read_wcs_from_header(f[1].header) crpix = whdr['CRPIX'] shift = models.Shift(crpix[0]) & models.Shift(crpix[1]) rotation = models.AffineTransformation2D(matrix=whdr['PC']) cdelt = whdr['CDELT'] scale = models.Scale(cdelt[0]) & models.Scale(cdelt[1]) #print util.get_projcode(whdr['CTYPE'][0]) tan = models.Pix2Sky_TAN() crval = whdr['CRVAL'] n2c = models.RotateNative2Celestial(crval[0], crval[1], 180) foc2sky = (shift | rotation | scale | tan | n2c).rename('foc2sky') fasdf = AsdfFile() fasdf.tree = {'model': foc2sky} fasdf.write_to('foc2sky.asdf')
def test_fix_inputs(tmpdir): with warnings.catch_warnings(): # Some schema files are missing from asdf<=2.4.2 which causes warnings if Version(asdf.__version__) <= Version('2.5.1'): warnings.filterwarnings('ignore', 'Unable to locate schema file') model0 = astmodels.Pix2Sky_TAN() model0.input_units_equivalencies = {'x': u.dimensionless_angles(), 'y': u.dimensionless_angles()} model1 = astmodels.Rotation2D() model = model0 | model1 tree = { 'compound': fix_inputs(model, {'x': 45}), 'compound1': fix_inputs(model, {0: 45}) } helpers.assert_roundtrip_tree(tree, tmpdir)
def varying_celestial_transform_from_tables( crpix: Union[Iterable[float], u.Quantity], cdelt: Union[Iterable[float], u.Quantity], pc_table: Union[ArrayLike, u.Quantity], crval_table: Union[Iterable[float], u.Quantity], lon_pole: Union[float, u.Quantity] = None, projection: Model = m.Pix2Sky_TAN(), inverse=False, slit=False, ) -> BaseVaryingCelestialTransform: """ Generate a `.BaseVaryingCelestialTransform` based on the dimensionality of the tables. """ table_shape, _, _ = BaseVaryingCelestialTransform._validate_table_shapes( pc_table, crval_table) if (table_d := len(table_shape)) not in (1, 2): raise ValueError( "Only one or two dimensional lookup tables are supported.")
def test_from_fiducial_sky(): sky = coord.SkyCoord(1.63 * u.radian, -72.4 * u.deg, frame='fk5') tan = models.Pix2Sky_TAN() w = wcs_from_fiducial(sky, projection=tan) assert isinstance(w.CelestialFrame.reference_frame, coord.FK5) assert_allclose(w(.1, .1), (93.7210280925364, -72.29972666307474))
model = TInputFormatter() result = model([1, 1], [2, 2]) assert_allclose(result, (np.array([1, 1]), np.array([2, 2]))) def test_format_input_arrays_transposed(): model = TInputFormatter() input = np.array([[1, 1]]).T, np.array([[2, 2]]).T result = model(*input) assert_allclose(result, input) @pytest.mark.parametrize('model', [ models.Gaussian2D(), models.Polynomial2D(1, ), models.Pix2Sky_TAN(), models.Tabular2D(lookup_table=np.ones((4, 5))) ]) @pytest.mark.skipif('not HAS_SCIPY') def test_call_keyword_args_2(model): """ Test calling a model with positional, keywrd and a mixture of both arguments. """ positional = model(1, 2) assert_allclose(positional, model(x=1, y=2)) assert_allclose(positional, model(1, y=2)) model.inputs = ('r', 't') assert_allclose(positional, model(r=1, t=2)) assert_allclose(positional, model(1, t=2)) assert_allclose(positional, model(1, 2))
def wcs_from_footprints(dmodels, refmodel=None, transform=None, bounding_box=None, pscale_ratio=None): """ Create a WCS from a list of input data models. A fiducial point in the output coordinate frame is created from the footprints of all WCS objects. For a spatial frame this is the center of the union of the footprints. For a spectral frame the fiducial is in the beginning of the footprint range. If ``refmodel`` is None, the first WCS object in the list is considered a reference. The output coordinate frame and projection (for celestial frames) is taken from ``refmodel``. If ``transform`` is not suplied, a compound transform is created using CDELTs and PC. If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed from bounding_box of all input WCSs. Parameters ---------- dmodels : list of `~jwst.datamodels.DataModel` A list of data models. refmodel : `~jwst.datamodels.DataModel`, optional This model's WCS is used as a reference. WCS. The output coordinate frame, the projection and a scaling and rotation transform is created from it. If not supplied the first model in the list is used as ``refmodel``. transform : `~astropy.modeling.core.Model`, optional A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial` If not supplied Scaling | Rotation is computed from ``refmodel``. bounding_box : tuple, optional Bounding_box of the new WCS. If not supplied it is computed from the bounding_box of all inputs. pscale_ratio : float, optional Ratio of input to output pixel scale. """ bb = bounding_box wcslist = [im.meta.wcs for im in dmodels] if not isiterable(wcslist): raise ValueError("Expected 'wcslist' to be an iterable of WCS objects.") if not all([isinstance(w, WCS) for w in wcslist]): raise TypeError("All items in wcslist are to be instances of gwcs.WCS.") if refmodel is None: refmodel = dmodels[0] else: if not isinstance(refmodel, DataModel): raise TypeError("Expected refmodel to be an instance of DataModel.") fiducial = compute_fiducial(wcslist, bb) ref_fiducial = compute_fiducial([refmodel.meta.wcs]) prj = astmodels.Pix2Sky_TAN() if transform is None: transform = [] wcsinfo = pointing.wcsinfo_from_model(refmodel) sky_axes, spec, other = gwutils.get_axes(wcsinfo) # Need to put the rotation matrix (List[float, float, float, float]) # returned from calc_rotation_matrix into the correct shape for # constructing the transformation roll_ref = np.deg2rad(refmodel.meta.wcsinfo.roll_ref) v3yangle = np.deg2rad(refmodel.meta.wcsinfo.v3yangle) vparity = refmodel.meta.wcsinfo.vparity pc = np.reshape( calc_rotation_matrix(roll_ref, v3yangle, vparity=vparity), (2, 2) ) rotation = astmodels.AffineTransformation2D(pc) transform.append(rotation) if sky_axes: scale = compute_scale(refmodel.meta.wcs, ref_fiducial, pscale_ratio=pscale_ratio) transform.append(astmodels.Scale(scale) & astmodels.Scale(scale)) if transform: transform = functools.reduce(lambda x, y: x | y, transform) out_frame = refmodel.meta.wcs.output_frame input_frame = dmodels[0].meta.wcs.input_frame wnew = wcs_from_fiducial(fiducial, coordinate_frame=out_frame, projection=prj, transform=transform, input_frame=input_frame) footprints = [w.footprint().T for w in wcslist] domain_bounds = np.hstack([wnew.backward_transform(*f) for f in footprints]) for axs in domain_bounds: axs -= (axs.min() + .5) output_bounding_box = [] for axis in out_frame.axes_order: axis_min, axis_max = domain_bounds[axis].min(), domain_bounds[axis].max() output_bounding_box.append((axis_min, axis_max)) output_bounding_box = tuple(output_bounding_box) ax1, ax2 = np.array(output_bounding_box)[sky_axes] offset1 = (ax1[1] - ax1[0]) / 2 offset2 = (ax2[1] - ax2[0]) / 2 offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2) wnew.insert_transform('detector', offsets, after=True) wnew.bounding_box = output_bounding_box return wnew
def wcs_from_footprints(dmodels, refmodel=None, transform=None, bounding_box=None, domain=None): """ Create a WCS from a list of input data models. A fiducial point in the output coordinate frame is created from the footprints of all WCS objects. For a spatial frame this is the center of the union of the footprints. For a spectral frame the fiducial is in the beginning of the footprint range. If ``refmodel`` is None, the first WCS object in the list is considered a reference. The output coordinate frame and projection (for celestial frames) is taken from ``refmodel``. If ``transform`` is not suplied, a compound transform is created using CDELTs and PC. If ``bounding_box`` is not supplied, the bounding_box of the new WCS is computed from bounding_box of all input WCSs. Parameters ---------- dmodels : list of `~jwst.datamodels.DataModel` A list of data models. refmodel : `~jwst.datamodels.DataModel`, optional This model's WCS is used as a reference. WCS. The output coordinate frame, the projection and a scaling and rotation transform is created from it. If not supplied the first model in the list is used as ``refmodel``. transform : `~astropy.modeling.core.Model`, optional A transform, passed to :meth:`~gwcs.wcstools.wcs_from_fiducial` If not supplied Scaling | Rotation is computed from ``refmodel``. bounding_box : tuple, optional Bounding_box of the new WCS. If not supplied it is computed from the bounding_box of all inputs. """ if domain is not None: warnings.warning( "'domain' was deprecated in 0.8 and will be removed from next" "version. Use 'bounding_box' instead.") bb = _domain_to_bounding_box(domain) else: bb = bounding_box wcslist = [im.meta.wcs for im in dmodels] if not isiterable(wcslist): raise ValueError( "Expected 'wcslist' to be an iterable of WCS objects.") if not all([isinstance(w, WCS) for w in wcslist]): raise TypeError( "All items in wcslist are to be instances of gwcs.WCS.") if refmodel is None: refmodel = dmodels[0] else: if not isinstance(refmodel, DataModel): raise TypeError( "Expected refmodel to be an instance of DataModel.") fiducial = compute_fiducial(wcslist, bb) prj = astmodels.Pix2Sky_TAN() if transform is None: transform = [] wcsinfo = pointing.wcsinfo_from_model(refmodel) sky_axes, spec, other = gwutils.get_axes(wcsinfo) rotation = astmodels.AffineTransformation2D(wcsinfo['PC']) transform.append(rotation) if sky_axes: cdelt1, cdelt2 = wcsinfo['CDELT'][sky_axes] scale = np.sqrt(np.abs(cdelt1 * cdelt2)) scales = astmodels.Scale(scale) & astmodels.Scale(scale) transform.append(scales) if transform: transform = functools.reduce(lambda x, y: x | y, transform) out_frame = refmodel.meta.wcs.output_frame wnew = wcs_from_fiducial(fiducial, coordinate_frame=out_frame, projection=prj, transform=transform) footprints = [w.footprint().T for w in wcslist] domain_bounds = np.hstack( [wnew.backward_transform(*f) for f in footprints]) for axs in domain_bounds: axs -= axs.min() bounding_box = [] for axis in out_frame.axes_order: axis_min, axis_max = domain_bounds[axis].min( ), domain_bounds[axis].max() bounding_box.append((axis_min, axis_max)) bounding_box = tuple(bounding_box) ax1, ax2 = np.array(bounding_box)[sky_axes] offset1 = (ax1[1] - ax1[0]) / 2 offset2 = (ax2[1] - ax2[0]) / 2 offsets = astmodels.Shift(-offset1) & astmodels.Shift(-offset2) wnew.insert_transform('detector', offsets, after=True) wnew.bounding_box = bounding_box return wnew