def test_compound_model_with_nonstandard_broadcasting(): """ Ensure that the ``standard_broadcasting`` flag is properly propagated when creating compound models. See the commit message for the commit in which this was added for more details. """ offx = Shift(1) offy = Shift(2) rot = AffineTransformation2D([[0, -1], [1, 0]]) m = (offx & offy) | rot x, y = m(0, 0) assert x == -2 assert y == 1 # make sure conversion back to scalars is working properly assert isinstance(x, float) assert isinstance(y, float) x, y = m([0, 1, 2], [0, 1, 2]) assert np.all(x == [-2, -3, -4]) assert np.all(y == [1, 2, 3])
def compute_output_transform(refwcs, filename, fiducial): """Compute a simple FITS-type WCS transform """ x0, y0 = refwcs.backward_transform(*fiducial) x1 = x0 + 1 y1 = y0 + 1 ra0, dec0 = refwcs(x0, y0) ra_xdir, dec_xdir = refwcs(x1, y0) ra_ydir, dec_ydir = refwcs(x0, y1) position0 = SkyCoord(ra=ra0, dec=dec0, unit='deg') position_xdir = SkyCoord(ra=ra_xdir, dec=dec_xdir, unit='deg') position_ydir = SkyCoord(ra=ra_ydir, dec=dec_ydir, unit='deg') offset_xdir = position0.spherical_offsets_to(position_xdir) offset_ydir = position0.spherical_offsets_to(position_ydir) xscale = np.abs(position0.separation(position_xdir).value) yscale = np.abs(position0.separation(position_ydir).value) scale = np.sqrt(xscale * yscale) c00 = offset_xdir[0].value / scale c01 = offset_xdir[1].value / scale c10 = offset_ydir[0].value / scale c11 = offset_ydir[1].value / scale pc_matrix = AffineTransformation2D(matrix=[[c00, c01], [c10, c11]]) cdelt = Scale(scale) & Scale(scale) return pc_matrix | cdelt
def test_slicing_on_instance_with_parameterless_model(): """ Regression test to fix an issue where the indices attached to parameter names on a compound model were not handled properly when one or more submodels have no parameters. This was especially evident in slicing. """ p2 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3) p1 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3) mapping = Mapping((0, 1, 0, 1)) offx = Shift(-2, name='x_translation') offy = Shift(-1, name='y_translation') aff = AffineTransformation2D(matrix=[[1, 2], [3, 4]], name='rotation') model = mapping | (p1 & p2) | (offx & offy) | aff assert model.param_names == ('c0_0_1', 'c1_0_1', 'c0_1_1', 'c0_0_2', 'c1_0_2', 'c0_1_2', 'offset_3', 'offset_4', 'matrix_5', 'translation_5') assert model(1, 2) == (23.0, 53.0) m = model[3:] assert m.param_names == ('offset_3', 'offset_4', 'matrix_5', 'translation_5') assert m(1, 2) == (1.0, 1.0)
def _tpcorr_init(v2_ref, v3_ref, roll_ref): s2c = SphericalToCartesian(name='s2c', wrap_lon_at=180) c2s = CartesianToSpherical(name='c2s', wrap_lon_at=180) unit_conv = Scale(1.0 / 3600.0, name='arcsec_to_deg_1D') unit_conv = unit_conv & unit_conv unit_conv.name = 'arcsec_to_deg_2D' unit_conv_inv = Scale(3600.0, name='deg_to_arcsec_1D') unit_conv_inv = unit_conv_inv & unit_conv_inv unit_conv_inv.name = 'deg_to_arcsec_2D' affine = AffineTransformation2D(name='tp_affine') affine_inv = AffineTransformation2D(name='tp_affine_inv') rot = RotationSequence3D([v2_ref, -v3_ref, roll_ref], 'zyx', name='det_to_optic_axis') rot_inv = rot.inverse rot_inv.name = 'optic_axis_to_det' # projection submodels: c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping( (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt')) c2tan.name = 'Cartesian 3D to TAN' tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') | (Const1D(1, name='one') & Identity(2, name='I(2D)'))) tan2c.name = 'TAN to cartesian 3D' total_corr = (unit_conv | s2c | rot | c2tan | affine | tan2c | rot_inv | c2s | unit_conv_inv) total_corr.name = 'JWST tangent-plane linear correction. v1' inv_total_corr = (unit_conv | s2c | rot | c2tan | affine_inv | tan2c | rot_inv | c2s | unit_conv_inv) inv_total_corr.name = 'Inverse JWST tangent-plane linear correction. v1' # TODO # re-enable circular inverse definitions once # https://github.com/spacetelescope/asdf/issues/744 or # https://github.com/spacetelescope/asdf/issues/745 are resolved. # # inv_total_corr.inverse = total_corr total_corr.inverse = inv_total_corr return total_corr
def _make_reference_gwcs_wcs(fits_hdr): hdr = fits.Header.fromfile(get_pkg_data_filename(fits_hdr)) fw = fitswcs.WCS(hdr) unit_conv = Scale(1.0 / 3600.0, name='arcsec_to_deg_1D') unit_conv = unit_conv & unit_conv unit_conv.name = 'arcsec_to_deg_2D' unit_conv_inv = Scale(3600.0, name='deg_to_arcsec_1D') unit_conv_inv = unit_conv_inv & unit_conv_inv unit_conv_inv.name = 'deg_to_arcsec_2D' c2s = CartesianToSpherical(name='c2s', wrap_lon_at=180) s2c = SphericalToCartesian(name='s2c', wrap_lon_at=180) c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping( (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt')) c2tan.name = 'Cartesian 3D to TAN' tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') | (Const1D(1, name='one') & Identity(2, name='I(2D)'))) tan2c.name = 'TAN to cartesian 3D' tan2c.inverse = c2tan c2tan.inverse = tan2c aff = AffineTransformation2D(matrix=fw.wcs.cd) offx = Shift(-fw.wcs.crpix[0]) offy = Shift(-fw.wcs.crpix[1]) s = 5e-6 scale = Scale(s) & Scale(s) det2tan = (offx & offy) | scale | tan2c | c2s | unit_conv_inv taninv = s2c | c2tan tan = Pix2Sky_TAN() n2c = RotateNative2Celestial(fw.wcs.crval[0], fw.wcs.crval[1], 180) wcslin = unit_conv | taninv | scale.inverse | aff | tan | n2c sky_frm = cf.CelestialFrame(reference_frame=coord.ICRS()) det_frm = cf.Frame2D(name='detector') v2v3_frm = cf.Frame2D(name="v2v3", unit=(u.arcsec, u.arcsec), axes_names=('x', 'y'), axes_order=(0, 1)) pipeline = [(det_frm, det2tan), (v2v3_frm, wcslin), (sky_frm, None)] gw = gwcs.WCS(input_frame=det_frm, output_frame=sky_frm, forward_transform=pipeline) gw.crpix = fw.wcs.crpix gw.crval = fw.wcs.crval gw.bounding_box = ((-0.5, fw.pixel_shape[0] - 0.5), (-0.5, fw.pixel_shape[1] - 0.5)) return gw
def _tpcorr_combine_affines(tpcorr, matrix, shift): AffineTransformation2D(matrix, shift) # check input parameters are OK m = np.dot(matrix, tpcorr['tp_affine'].matrix.value) t = np.dot(matrix, tpcorr['tp_affine'].translation.value) + shift tpcorr['tp_affine'].matrix = m tpcorr['tp_affine'].translation = t # update the affine transformation of the inverse model as well: invm = np.linalg.inv(m) tpcorr.inverse['tp_affine_inv'].matrix = invm tpcorr.inverse['tp_affine_inv'].translation = -np.dot(invm, t)
def create_DetToV2V3(v2ref=0.0, v3ref=0.0, roll=0.0, cd=[[1.0, 0.0], [0.0, 1.0]], crpix=[0, 0]): tpcorr = JWSTgWCS._tpcorr_init(v2_ref=v2ref, v3_ref=v3ref, roll_ref=roll) afinv = AffineTransformation2D(cd, -np.dot(cd, crpix)).inverse JWSTgWCS._tpcorr_combine_affines(tpcorr, afinv.matrix.value, afinv.translation.value) p = JWSTgWCS._v2v3_to_tpcorr_from_full(tpcorr) partial_tpcorr = p.inverse partial_tpcorr.inverse = p return partial_tpcorr
def map_to_transform(smap): # crval1u, crval2u = smap.reference_coordinate.Tx, smap.reference_coordinate.Ty # cdelt1u, cdelt2u = smap.scale # pcu = smap.rotation_matrix * u.arcsec # # First, shift the reference pixel from FITS (1) to Python (0) indexing # crpix1, crpix2 = u.Quantity(smap.reference_pixel) - 1 * u.pixel # # Then FITS WCS uses the negative of this value as the shift. # shiftu = Shift(-crpix1) & Shift(-crpix2) # # Next we define the Affine Transform. # # This also includes the pixel scale operation by using equivalencies # scale_e = {a: u.pixel_scale(scale) for a, scale in zip('xy', smap.scale)} # rotu = AffineTransformation2D(pcu, translation=(0, 0) * u.arcsec) # rotu.input_units_equivalencies = scale_e # # Handle the projection # tanu = Pix2Sky_TAN() # # Rotate from native spherical to celestial spherical coordinates # skyrotu = RotateNative2Celestial(crval1u, crval2u, 180 * u.deg) # # Combine the whole pipeline into one compound model # transu = shiftu | rotu | tanu | skyrotu crpix1u, crpix2u = u.Quantity(smap.reference_pixel) - 1 * u.pixel crval1u, crval2u = smap.reference_coordinate.Tx, smap.reference_coordinate.Ty cdelt1u, cdelt2u = smap.scale pcu = smap.rotation_matrix * u.arcsec shiftu = Shift(-crpix1u) & Shift(-crpix2u) scaleu = Multiply(cdelt1u) & Multiply(cdelt2u) rotu = AffineTransformation2D(pcu, translation=(0, 0) * u.arcsec) tanu = Pix2Sky_TAN() skyrotu = RotateNative2Celestial(crval1u, crval2u, 180 * u.deg) transu = shiftu | scaleu | rotu | tanu | skyrotu transu.rename("spatial") return transu
def spatial_model_from_quantity(crpix1, crpix2, cdelt1, cdelt2, pc, crval1, crval2, projection='TAN'): """ Given quantity representations of a HPLx FITS WCS return a model for the spatial transform. The ordering of ctype1 and ctype2 should be LON, LAT """ # TODO: Find this from somewhere else or extend it or something projections = {'TAN': Pix2Sky_TAN()} shiftu = Shift(-crpix1) & Shift(-crpix2) scale = Multiply(cdelt1) & Multiply(cdelt2) rotu = AffineTransformation2D(pc, translation=(0, 0) * u.arcsec) tanu = projections[projection] skyrotu = RotateNative2Celestial(crval1, crval2, 180 * u.deg) return shiftu | scale | rotu | tanu | skyrotu
def _make_gwcs_wcs(fits_hdr): hdr = fits.Header.fromfile(get_pkg_data_filename(fits_hdr)) fw = fitswcs.WCS(hdr) a_order = hdr['A_ORDER'] a_coeff = {} for i in range(a_order + 1): for j in range(a_order + 1 - i): key = 'A_{:d}_{:d}'.format(i, j) if key in hdr: a_coeff[key] = hdr[key] b_order = hdr['B_ORDER'] b_coeff = {} for i in range(b_order + 1): for j in range(b_order + 1 - i): key = 'B_{:d}_{:d}'.format(i, j) if key in hdr: b_coeff[key] = hdr[key] cx = {"c" + k[2:]: v for k, v in a_coeff.items()} cy = {"c" + k[2:]: v for k, v in b_coeff.items()} sip_distortion = ((Shift(-fw.wcs.crpix[0]) & Shift(-fw.wcs.crpix[1])) | Mapping((0, 1, 0, 1)) | (polynomial.Polynomial2D(a_order, **cx, c1_0=1) & polynomial.Polynomial2D(b_order, **cy, c0_1=1)) | (Shift(fw.wcs.crpix[0]) & Shift(fw.wcs.crpix[1]))) y, x = np.indices(fw.array_shape) unit_conv = Scale(1.0 / 3600.0, name='arcsec_to_deg_1D') unit_conv = unit_conv & unit_conv unit_conv.name = 'arcsec_to_deg_2D' unit_conv_inv = Scale(3600.0, name='deg_to_arcsec_1D') unit_conv_inv = unit_conv_inv & unit_conv_inv unit_conv_inv.name = 'deg_to_arcsec_2D' c2s = CartesianToSpherical(name='c2s', wrap_lon_at=180) s2c = SphericalToCartesian(name='s2c', wrap_lon_at=180) c2tan = ((Mapping((0, 1, 2), name='xyz') / Mapping( (0, 0, 0), n_inputs=3, name='xxx')) | Mapping((1, 2), name='xtyt')) c2tan.name = 'Cartesian 3D to TAN' tan2c = (Mapping((0, 0, 1), n_inputs=2, name='xtyt2xyz') | (Const1D(1, name='one') & Identity(2, name='I(2D)'))) tan2c.name = 'TAN to cartesian 3D' tan2c.inverse = c2tan c2tan.inverse = tan2c aff = AffineTransformation2D(matrix=fw.wcs.cd) offx = Shift(-fw.wcs.crpix[0]) offy = Shift(-fw.wcs.crpix[1]) s = 5e-6 scale = Scale(s) & Scale(s) sip_distortion |= (offx & offy) | scale | tan2c | c2s | unit_conv_inv taninv = s2c | c2tan tan = Pix2Sky_TAN() n2c = RotateNative2Celestial(fw.wcs.crval[0], fw.wcs.crval[1], 180) wcslin = unit_conv | taninv | scale.inverse | aff | tan | n2c sky_frm = cf.CelestialFrame(reference_frame=coord.ICRS()) det_frm = cf.Frame2D(name='detector') v2v3_frm = cf.Frame2D(name="v2v3", unit=(u.arcsec, u.arcsec), axes_names=('x', 'y'), axes_order=(0, 1)) pipeline = [(det_frm, sip_distortion), (v2v3_frm, wcslin), (sky_frm, None)] gw = gwcs.WCS(input_frame=det_frm, output_frame=sky_frm, forward_transform=pipeline) gw.crpix = fw.wcs.crpix gw.crval = fw.wcs.crval gw.bounding_box = ((-0.5, fw.pixel_shape[0] - 0.5), (-0.5, fw.pixel_shape[1] - 0.5)) # sanity check: for _ in range(100): x = np.random.randint(1, fw.pixel_shape[0]) y = np.random.randint(1, fw.pixel_shape[1]) assert np.allclose(gw(x, y), fw.all_pix2world(x, y, 1), rtol=0, atol=1e-11) return gw