def test_pixel_to_pixel_correlated(): wcs_in = WCS(naxis=2) wcs_in.wcs.ctype = 'DEC--TAN', 'RA---TAN' wcs_in.wcs.set() wcs_out = WCS(naxis=2) wcs_out.wcs.ctype = 'GLON-CAR', 'GLAT-CAR' wcs_out.wcs.set() # First try with scalars x, y = pixel_to_pixel(wcs_in, wcs_out, 1, 2) assert x.shape == () assert y.shape == () # Now try with broadcasted arrays x = np.linspace(10, 20, 10) y = np.linspace(10, 20, 20) Y1, X1 = np.meshgrid(y, x, indexing='ij', copy=False) Y2, X2 = pixel_to_pixel(wcs_in, wcs_out, X1, Y1) # The final arrays should have the correct shape assert X2.shape == (20, 10) assert Y2.shape == (20, 10) # and there are no efficiency gains here since the celestial axes are correlated assert unbroadcast(X2).shape == (20, 10)
def test_pixel_to_pixel_1d(): # Simple test to make sure that when WCS only returns one world coordinate # this still works correctly (since this requires special treatment behind # the scenes). wcs_in = WCS(naxis=1) wcs_in.wcs.ctype = 'COORD1', wcs_in.wcs.cunit = 'nm', wcs_in.wcs.set() wcs_out = WCS(naxis=1) wcs_out.wcs.ctype = 'COORD2', wcs_out.wcs.cunit = 'cm', wcs_out.wcs.set() # First try with a scalar x = pixel_to_pixel(wcs_in, wcs_out, 1) assert x.shape == () # Next with a regular array x = np.linspace(10, 20, 10) x = pixel_to_pixel(wcs_in, wcs_out, x) assert x.shape == (10, ) # And now try with a broadcasted array x = np.broadcast_to(np.linspace(10, 20, 10), (4, 10)) x = pixel_to_pixel(wcs_in, wcs_out, x) assert x.shape == (4, 10) # The broadcasting of the input should be retained assert unbroadcast(x).shape == (10, )
def test_pixel_to_pixel(): wcs_in = WCS(naxis=3) wcs_in.wcs.ctype = 'DEC--TAN', 'FREQ', 'RA---TAN' wcs_in.wcs.set() wcs_out = WCS(naxis=3) wcs_out.wcs.ctype = 'GLON-CAR', 'GLAT-CAR', 'FREQ' wcs_out.wcs.set() # First try with scalars with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): x, y, z = pixel_to_pixel(wcs_in, wcs_out, 1, 2, 3) assert x.shape == () assert y.shape == () assert z.shape == () # Now try with broadcasted arrays x = np.linspace(10, 20, 10) y = np.linspace(10, 20, 20) z = np.linspace(10, 20, 30) Z1, Y1, X1 = np.meshgrid(z, y, x, indexing='ij', copy=False) with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): X2, Y2, Z2 = pixel_to_pixel(wcs_in, wcs_out, X1, Y1, Z1) # The final arrays should have the correct shape assert X2.shape == (30, 20, 10) assert Y2.shape == (30, 20, 10) assert Z2.shape == (30, 20, 10) # But behind the scenes should also be broadcasted assert unbroadcast(X2).shape == (30, 1, 10) assert unbroadcast(Y2).shape == (30, 1, 10) assert unbroadcast(Z2).shape == (20, 1) # We can put the values back through the function to ensure round-tripping with pytest.warns(AstropyUserWarning, match='No observer defined on WCS'): X3, Y3, Z3 = pixel_to_pixel(wcs_out, wcs_in, X2, Y2, Z2) # The final arrays should have the correct shape assert X2.shape == (30, 20, 10) assert Y2.shape == (30, 20, 10) assert Z2.shape == (30, 20, 10) # But behind the scenes should also be broadcasted assert unbroadcast(X3).shape == (30, 1, 10) assert unbroadcast(Y3).shape == (20, 1) assert unbroadcast(Z3).shape == (30, 1, 10) # And these arrays should match the input assert_allclose(X1, X3) assert_allclose(Y1, Y3) assert_allclose(Z1, Z3)
def _pixel_to_pixel(pixels, wcs): """ Convenience function that wraps astropy.wcs.utils.pixel_to_pixel and maps SLW cube pixels to nearest SSW cube pixels and vice versa. Parameters ---------- pixels : dictionary Dictionary containing the SLW and SSW pixels to be mapped. Format should be {'SLW': [[cols], [rows]], 'SSW': [[cols], [rows]]} for multiple pixels, or {'SLW': [col, row], 'SSW': [col, row]} for a single pixel. Both SPIRE bands are not required. wcs : dictionary of WCS Dictionary of WCS for SLW and SSW bands. see `_make_wcs`. Returns ------- output : dictionary Dictionary of mapped pixels. Format matches `pixels` with reciprocal SPIRE band keys. """ swap = {'SLW': 'SSW', 'SSW': 'SLW'} output = dict() for ary, pix in pixels.items(): pix = np.array(pix) output[swap[ary]] = np.round( pixel_to_pixel(wcs[ary], wcs[swap[ary]], *pix), 0).astype(int).tolist() return output
def identify_invariant_axes(source_wcs, target_wcs, input_shape, atol=1e-6, rtol=1e-6): """ Performs a pixel to pixel transformation to identify if there are any invariant axes between the given source and target WCS objects. Parameters ---------- source_wcs: `astropy.wcs.wcsapi.BaseHighLevelWCS` or `astropy.wcs.wcsapi.BaseLowLevelWCS` target_wcs: `astropy.wcs.wcsapi.BaseHighLevelWCS` or `astropy.wcs.wcsapi.BaseLowLevelWCS` input_shape: `tuple` The array shape of the data. atol: `float` The absolute tolerance parameter for comparison. rtol: `float` The relative tolerance parameter for comparison. Returns ------- result: `list` A list of booleans denoting whether the axis is invariant or not. Follows the WCS ordering. """ input_pixel_coords = np.meshgrid(*[np.arange(n) for n in input_shape]) output_pixel_coords = pixel_to_pixel(source_wcs, target_wcs, *input_pixel_coords) return [ np.allclose(input_coord, output_coord, atol=atol, rtol=rtol) for input_coord, output_coord in zip( input_pixel_coords, output_pixel_coords) ]
def backwards(*pixel_input): return pixel_to_pixel(wcs2, wcs1, *pixel_input)
def forwards(*pixel_input): return pixel_to_pixel(wcs1, wcs2, *pixel_input)
def add_single_spectra_to_map( spectra_map, *, header, data, spec_info=None, wcs_info=None, units_info=None, purpose_prefix=None, all_standard_units, all_keywords, valid_wcs, index=None, ): spec_wcs_info = {} spec_units_info = {} if wcs_info is not None: spec_wcs_info.update(wcs_info) if units_info is not None: spec_units_info.update(units_info) if spec_info is not None: spec_wcs_info.update(spec_info.get("wcs", {})) spec_units_info.update(spec_info.get("units", {})) purpose = spec_info.get("purpose") else: purpose = None purpose = get_purpose( header, purpose=purpose, purpose_prefix=purpose_prefix, all_keywords=all_keywords, index=index, ) if purpose == Purpose.SKIP: return None if valid_wcs or not spec_wcs_info: wcs = WCS(header) else: wcs = compute_wcs_from_keys_and_values(header, **spec_wcs_info) if all_standard_units: spec_units_info = {"flux_unit_keyword": "BUNIT"} flux_unit = get_flux_units_from_keys_and_values(header, **spec_units_info) flux = data * flux_unit meta = {"header": header, "purpose": PURPOSE_SPECTRA_MAP[purpose]} if purpose in CREATE_SPECTRA: spectrum = Spectrum1D(wcs=wcs, flux=flux, meta=meta) spectra_map[PURPOSE_SPECTRA_MAP[purpose]].append(spectrum) elif purpose in ERROR_PURPOSES: try: spectrum = spectra_map[PURPOSE_SPECTRA_MAP[purpose]][-1] except IndexError: raise ValueError(f"No spectra to associate with {purpose}") aligned_flux = pixel_to_pixel(wcs, spectrum.wcs, flux) spectrum.uncertainty = UNCERTAINTY_MAP[purpose](aligned_flux) spectrum.meta["uncertainty_header"] = header # We never actually want to return something, this just flags it to pylint # that we know we're breaking out of the function when skip is selected return None