Пример #1
0
def test_fit_wcs_from_points_CRPIX_bounds():
    # Test CRPIX bounds requirement
    wcs_str = """
WCSAXES =                    2 / Number of coordinate axes
CRPIX1  =               1045.0 / Pixel coordinate of reference point
CRPIX2  =               1001.0 / Pixel coordinate of reference point
PC1_1   =  0.00056205870415378 / Coordinate transformation matrix element
PC1_2   =    -0.00569181083243 / Coordinate transformation matrix element
PC2_1   =   0.0056776810932466 / Coordinate transformation matrix element
PC2_2   =   0.0004208048403273 / Coordinate transformation matrix element
CDELT1  =                  1.0 / [deg] Coordinate increment at reference point
CDELT2  =                  1.0 / [deg] Coordinate increment at reference point
CUNIT1  = 'deg'                / Units of coordinate increment and value
CUNIT2  = 'deg'                / Units of coordinate increment and value
CTYPE1  = 'RA---TAN'           / Right ascension, gnomonic projection
CTYPE2  = 'DEC--TAN'           / Declination, gnomonic projection
CRVAL1  =      104.57797893504 / [deg] Coordinate value at reference point
CRVAL2  =     -74.195502593322 / [deg] Coordinate value at reference point
LONPOLE =                180.0 / [deg] Native longitude of celestial pole
LATPOLE =     -74.195502593322 / [deg] Native latitude of celestial pole
TIMESYS = 'TDB'                / Time scale
TIMEUNIT= 'd'                  / Time units
DATEREF = '1858-11-17'         / ISO-8601 fiducial time
MJDREFI =                  0.0 / [d] MJD of fiducial time, integer part
MJDREFF =                  0.0 / [d] MJD of fiducial time, fractional part
DATE-OBS= '2019-03-27T03:30:13.832Z' / ISO-8601 time of observation
MJD-OBS =      58569.145993426 / [d] MJD of observation
MJD-OBS =      58569.145993426 / [d] MJD at start of observation
TSTART  =      1569.6467941661 / [d] Time elapsed since fiducial time at start
DATE-END= '2019-03-27T04:00:13.831Z' / ISO-8601 time at end of observation
MJD-END =      58569.166826748 / [d] MJD at end of observation
TSTOP   =      1569.6676274905 / [d] Time elapsed since fiducial time at end
TELAPSE =        0.02083332443 / [d] Elapsed time (start to stop)
TIMEDEL =    0.020833333333333 / [d] Time resolution
TIMEPIXR=                  0.5 / Reference position of timestamp in binned data
RADESYS = 'ICRS'               / Equatorial coordinate system
"""
    wcs_header = fits.Header.fromstring(wcs_str, sep='\n')
    ffi_wcs = WCS(wcs_header)

    yi, xi = (1000, 1000)
    y, x = (10, 200)

    center_coord = SkyCoord(ffi_wcs.all_pix2world([[xi + x // 2, yi + y // 2]],
                                                  0),
                            unit='deg')[0]
    ypix, xpix = [arr.flatten() for arr in np.mgrid[xi:xi + x, yi:yi + y]]
    world_pix = SkyCoord(*ffi_wcs.all_pix2world(xpix, ypix, 0), unit='deg')

    fit_wcs = fit_wcs_from_points((ypix, xpix), world_pix, proj_point='center')

    assert (fit_wcs.wcs.crpix.astype(int) == [1100, 1005]).all()
    assert fit_wcs.pixel_shape == (200, 10)
Пример #2
0
    def draw_guide_stars(cls, img, img_stars, pattern, max=20, color=(255, 255, 255)):
        """Given an image and a list of Centroids
        draw lines in the image between them in order.
        :param img: Image to draw in.
        :param img_stars: List of stars to draw lines to.
        :param pattern: Pattern of stars."""
        # Build WCS
        pixels_x = np.array([])
        pixels_y = np.array([])
        stars_ra = []
        stars_dec = []
        for found_star in pattern:
            if found_star.is_identified():
                pixels_x = np.append(pixels_x, found_star.centroid.x)
                pixels_y = np.append(pixels_y, found_star.centroid.y)
                stars_ra.append(found_star.real_star.ra)
                stars_dec.append(found_star.real_star.dec)
        stars = SkyCoord(ra=stars_ra, dec=stars_dec, unit=u.deg)
        wcs = fit_wcs_from_points((pixels_x, pixels_y), stars)

        img_stars_to_label = []
        for img_star in img_stars:
            for found_star in pattern:
                if found_star.centroid == img_star.centroid and found_star.is_identified():
                    img_star.labeled = True
            img_stars_to_label.append(img_star)

        # Set wcs coordinates to ImageStars
        for img_star in img_stars:
            pixel_x = np.array([[img_star.centroid.x]])
            pixel_y = np.array([[img_star.centroid.y]])
            coords_ra, coords_dec = wcs.wcs_pix2world(pixel_x, pixel_y, 0)
            coords = SkyCoord(ra=coords_ra, dec=coords_dec, unit=u.deg)
            img_star.set_wcs_coords(coords)

        labeled = 0
        for hip_number in catalog._guide_stars:
            star = catalog.get_star_by_id(int(hip_number))
            coords_a = SkyCoord(ra=star.ra, dec=star.dec, unit=u.deg)
            max = 10
            for img_star in img_stars_to_label[:max]:
                if img_star.is_labeled():
                    continue
                coords_b = img_star.get_wcs_coords()
                if coords_a.separation(coords_b) < 0.5 * u.deg:
                    center = (img_star.centroid.x - 20, img_star.centroid.y + 25)
                    cv2.putText(img, str(star.name), center,
                                cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 1)
                    labeled += 1
                    img_star.set_labeled()

        return labeled
Пример #3
0
def wcs_sip_fit(cat_df,
                init_wcs,
                sip_degree=3,
                x_key='xcentroid',
                y_key='ycentroid',
                alt_key='Alt',
                az_key='Az'):
    """
    Take an initial WCS and refine it with SIP distortion terms by fitting to a larger catalog in a pandas
    datafrom, cat_df. The input dataframe needs to have both X/Y image positions and object Alt/Az.
    """
    wcs_refined = fit_wcs_from_points(
        (cat_df[x_key].array, cat_df[y_key].array),
        SkyCoord(cat_df[az_key] * u.deg, cat_df[alt_key] * u.deg),
        projection=init_wcs,
        proj_point=SkyCoord(0 * u.deg, 90 * u.deg),
        sip_degree=sip_degree)
    return wcs_refined
Пример #4
0
def wcs():
    d = rotate()
    xyrot = (np.array(d['x2']), np.array(d['y2']))
    wcs = utils.fit_wcs_from_points(xyrot, coord, center)
    print(wcs)
    header = fits.Header()
    header.extend(wcs.to_header(), update=True)
    pc1_1 = header['PC1_1']
    scale = -pc1_1 * 2 / (np.sqrt(2))
    sin_a = pc1_1 / scale
    alpha = np.rad2deg(np.arcsin(sin_a))
    print(alpha)
    w = WCS(header)
    e = dict()
    world = w.wcs_pix2world(d['x2'], d['y2'], 0)
    e['xr'] = world[0]
    e['yr'] = world[1]
    return (e)
Пример #5
0
def wcs(xyrot):

    # Center of "sky L"
    #center = SkyCoord(ra=0.11, dec=0.11, unit=(u.deg,u.deg))

    # Coordinates of "sky L" expressed in ra,dec
    # ra,dec = ([0.11, 0.11, 0.11, 0.11, 0.12, 0.13],
    #           [0.14, 0.13, 0.12, 0.11, 0.11, 0.11] )

    center = SkyCoord(246.7368408, 43.480712949, frame = 'icrs', unit = (u.deg,u.deg))

    ra,dec = (np.array([246.75001315, 246.75001315, 246.72033646, 246.72303144,
                   246.74164072, 246.73540614, 246.73379121, 246.73761455,
                   246.7179495 , 246.73051123, 246.71970072, 246.7228646 ,
                   246.72647213, 246.7188386 , 246.7314031 , 246.71821002,
                   246.74785534, 246.73265223, 246.72579817, 246.71943263]),
             np.array([43.48690547,  43.48690547,  43.46792989,  43.48075238,
                   43.49560501,  43.48903538,  43.46045875,  43.47030776,
                   43.46132376,  43.48252763,  43.46802566,  43.46035331,
                   43.48218262,  43.46908299,  43.46131665,  43.46560591,
                   43.47791234,  43.45973025,  43.47208325,  43.47779988]))

    coord = SkyCoord(ra=ra, dec=dec, unit=(u.deg,u.deg))

    # Fitting "pixel L" and "sky L"
    wcs = utils.fit_wcs_from_points(xyrot, coord, center, sip_degree=2)

    # Coordinates of "sky L" expressed in pixel
    x,y = wcs.all_pix2world(ra,dec, 0)

    cd = wcs.wcs.cd # rotation matrix
    # norm = np.linalg.norm(cd) # norm
    # cd_norm = cd / norm

    ###
    fig = plt.figure(figsize=(6,6))
    ax = fig.add_subplot(111)
    ax.plot(xyrot[0],xyrot[1],'ob') # pixel L
    ax.plot(x,y,'xr')  # sky L in pixel
    #ax.plot(ra,dec,'xg')  # sky L in radec
    plt.savefig("filname.ps") # scusa, non mi va il terminale tk...
    plt.close('all')

    return cd
Пример #6
0
def test_issue10991():
    # test issue #10991 (it just needs to run and set the user defined crval)
    xy = np.array([[1766.88276168,  662.96432257,  171.50212526,  120.70924648],
               [1706.69832901, 1788.85480559, 1216.98949653, 1307.41843381]])
    world_coords = SkyCoord([(66.3542367 , 22.20000162), (67.15416174, 19.18042906),
                             (65.73375432, 17.54251555), (66.02400512, 17.44413253)],
                            frame="icrs", unit="deg")
    proj_point = SkyCoord(64.67514918, 19.63389538,
                          frame="icrs", unit="deg")

    fit_wcs = fit_wcs_from_points(
        xy=xy,
        world_coords=world_coords,
        proj_point=proj_point,
        projection='TAN'
    )
    projlon = proj_point.data.lon.deg
    projlat = proj_point.data.lat.deg
    assert (fit_wcs.wcs.crval == [projlon, projlat]).all()
Пример #7
0
def test_fit_wcs_from_points(header_str, crval, sip_degree, user_proj_point,
                             exp_max_dist, exp_std_dist):
    header = fits.Header.fromstring(header_str, sep='\n')
    header["CRVAL1"] = crval

    true_wcs = WCS(header, relax=True)

    # Getting the pixel coordinates
    x, y = np.meshgrid(list(range(10)), list(range(10)))
    x = x.flatten()
    y = y.flatten()

    # Calculating the true sky positions
    world_pix = true_wcs.pixel_to_world(x, y)

    # which projection point to use
    if user_proj_point:
        proj_point = world_pix[0]
        projlon = proj_point.data.lon.deg
        projlat = proj_point.data.lat.deg
    else:
        proj_point = 'center'

    # Fitting the wcs
    fit_wcs = fit_wcs_from_points((x, y),
                                  world_pix,
                                  proj_point=proj_point,
                                  sip_degree=sip_degree)

    # Validate that the true sky coordinates
    # match sky coordinates calculated from the wcs fit
    world_pix_new = fit_wcs.pixel_to_world(x, y)

    dists = world_pix.separation(world_pix_new)

    assert dists.max() < exp_max_dist
    assert np.std(dists) < exp_std_dist

    if user_proj_point:
        assert (fit_wcs.wcs.crval == [projlon, projlat]).all()
Пример #8
0
def test_fit_wcs_from_points():
    header_str_linear = """
XTENSION= 'IMAGE   '           / Image extension
BITPIX  =                  -32 / array data type
NAXIS   =                    2 / number of array dimensions
NAXIS1  =                   50
NAXIS2  =                   50
PCOUNT  =                    0 / number of parameters
GCOUNT  =                    1 / number of groups
RADESYS = 'ICRS    '
EQUINOX =               2000.0
WCSAXES =                    2
CTYPE1  = 'RA---TAN'
CTYPE2  = 'DEC--TAN'
CRVAL1  =    250.3497414839765
CRVAL2  =    2.280925599609063
CRPIX1  =               1045.0
CRPIX2  =               1001.0
CD1_1   =   -0.005564478186178
CD1_2   =   -0.001042099258152
CD2_1   =     0.00118144146585
CD2_2   =   -0.005590816683583
"""

    header_str_sip = """
XTENSION= 'IMAGE   '           / Image extension
BITPIX  =                  -32 / array data type
NAXIS   =                    2 / number of array dimensions
NAXIS1  =                   50
NAXIS2  =                   50
PCOUNT  =                    0 / number of parameters
GCOUNT  =                    1 / number of groups
RADESYS = 'ICRS    '
EQUINOX =               2000.0
WCSAXES =                    2
CTYPE1  = 'RA---TAN-SIP'
CTYPE2  = 'DEC--TAN-SIP'
CRVAL1  =    250.3497414839765
CRVAL2  =    2.280925599609063
CRPIX1  =               1045.0
CRPIX2  =               1001.0
CD1_1   =   -0.005564478186178
CD1_2   =   -0.001042099258152
CD2_1   =     0.00118144146585
CD2_2   =   -0.005590816683583
A_ORDER =                    2
B_ORDER =                    2
A_2_0   =    2.02451189234E-05
A_0_2   =   3.317603337918E-06
A_1_1   = 1.73456334971071E-05
B_2_0   =   3.331330003472E-06
B_0_2   = 2.04247482482589E-05
B_1_1   = 1.71476710804143E-05
AP_ORDER=                    2
BP_ORDER=                    2
AP_1_0  = 0.000904700296389636
AP_0_1  = 0.000627660715584716
AP_2_0  =  -2.023482905861E-05
AP_0_2  =  -3.332285841011E-06
AP_1_1  =  -1.731636633824E-05
BP_1_0  = 0.000627960882053211
BP_0_1  = 0.000911222886084808
BP_2_0  =  -3.343918167224E-06
BP_0_2  =  -2.041598249021E-05
BP_1_1  =  -1.711876336719E-05
A_DMAX  =    44.72893589844534
B_DMAX  =    44.62692873032506
"""
    header_linear = fits.Header.fromstring(header_str_linear, sep='\n')
    header_sip = fits.Header.fromstring(header_str_sip, sep='\n')

    true_wcs_linear = WCS(header_linear, relax=True)
    true_wcs_sip = WCS(header_sip, relax=True)

    # Getting the pixel coordinates
    x, y = np.meshgrid(list(range(10)), list(range(10)))
    x = x.flatten()
    y = y.flatten()

    # Calculating the true sky positions
    world_pix_linear = true_wcs_linear.pixel_to_world(x, y)
    world_pix_sip = true_wcs_sip.pixel_to_world(x, y)

    # Fitting the wcs, no distortion.
    fit_wcs_linear = fit_wcs_from_points((x, y),
                                         world_pix_linear,
                                         proj_point='center',
                                         sip_degree=None)

    # Fitting the wcs, with distortion.
    fit_wcs_sip = fit_wcs_from_points((x, y),
                                      world_pix_sip,
                                      proj_point='center',
                                      sip_degree=2)

    # Validate that the true sky coordinates calculated with `true_wcs_linear`
    # match sky coordinates calculated from the wcs fit with only linear terms

    world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y)

    dists = world_pix_linear.separation(world_pix_linear_new)

    assert dists.max() < 7e-5 * u.deg
    assert np.std(dists) < 2.5e-5 * u.deg

    # Validate that the true sky coordinates calculated with `true_wcs_sip`
    # match the sky coordinates calculated from the wcs fit with SIP of same
    # degree (2)

    world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y)
    dists = world_pix_sip.separation(world_pix_sip_new)

    assert dists.max() < 7e-6 * u.deg
    assert np.std(dists) < 2.5e-6 * u.deg

    # Test 360->0 degree crossover
    header_linear["CRVAL1"] = 352.3497414839765
    header_sip["CRVAL1"] = 352.3497414839765

    true_wcs_linear = WCS(header_linear, relax=True)
    true_wcs_sip = WCS(header_sip, relax=True)

    # Calculating the true sky positions
    world_pix_linear = true_wcs_linear.pixel_to_world(x, y)
    world_pix_sip = true_wcs_sip.pixel_to_world(x, y)

    # Fitting the wcs, no distortion.
    fit_wcs_linear = fit_wcs_from_points((x, y),
                                         world_pix_linear,
                                         proj_point='center',
                                         sip_degree=None)

    # Fitting the wcs, with distortion.
    fit_wcs_sip = fit_wcs_from_points((x, y),
                                      world_pix_sip,
                                      proj_point='center',
                                      sip_degree=2)

    # Validate that the true sky coordinates calculated with `true_wcs_linear`
    # match sky coordinates calculated from the wcs fit with only linear terms

    world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y)

    dists = world_pix_linear.separation(world_pix_linear_new)

    assert dists.max() < 7e-5 * u.deg
    assert np.std(dists) < 2.5e-5 * u.deg
Пример #9
0
def test_fit_wcs_from_points():
    header_str_linear = """
XTENSION= 'IMAGE   '           / Image extension
BITPIX  =                  -32 / array data type
NAXIS   =                    2 / number of array dimensions
NAXIS1  =                   50
NAXIS2  =                   50
PCOUNT  =                    0 / number of parameters
GCOUNT  =                    1 / number of groups
RADESYS = 'ICRS    '
EQUINOX =               2000.0
WCSAXES =                    2
CTYPE1  = 'RA---TAN'
CTYPE2  = 'DEC--TAN'
CRVAL1  =    250.3497414839765
CRVAL2  =    2.280925599609063
CRPIX1  =               1045.0
CRPIX2  =               1001.0
CD1_1   =   -0.005564478186178
CD1_2   =   -0.001042099258152
CD2_1   =     0.00118144146585
CD2_2   =   -0.005590816683583
"""

    header_str_sip = """
XTENSION= 'IMAGE   '           / Image extension
BITPIX  =                  -32 / array data type
NAXIS   =                    2 / number of array dimensions
NAXIS1  =                   50
NAXIS2  =                   50
PCOUNT  =                    0 / number of parameters
GCOUNT  =                    1 / number of groups
RADESYS = 'ICRS    '
EQUINOX =               2000.0
WCSAXES =                    2
CTYPE1  = 'RA---TAN-SIP'
CTYPE2  = 'DEC--TAN-SIP'
CRVAL1  =    250.3497414839765
CRVAL2  =    2.280925599609063
CRPIX1  =               1045.0
CRPIX2  =               1001.0
CD1_1   =   -0.005564478186178
CD1_2   =   -0.001042099258152
CD2_1   =     0.00118144146585
CD2_2   =   -0.005590816683583
A_ORDER =                    2
B_ORDER =                    2
A_2_0   =    2.02451189234E-05
A_0_2   =   3.317603337918E-06
A_1_1   = 1.73456334971071E-05
B_2_0   =   3.331330003472E-06
B_0_2   = 2.04247482482589E-05
B_1_1   = 1.71476710804143E-05
AP_ORDER=                    2
BP_ORDER=                    2
AP_1_0  = 0.000904700296389636
AP_0_1  = 0.000627660715584716
AP_2_0  =  -2.023482905861E-05
AP_0_2  =  -3.332285841011E-06
AP_1_1  =  -1.731636633824E-05
BP_1_0  = 0.000627960882053211
BP_0_1  = 0.000911222886084808
BP_2_0  =  -3.343918167224E-06
BP_0_2  =  -2.041598249021E-05
BP_1_1  =  -1.711876336719E-05
A_DMAX  =    44.72893589844534
B_DMAX  =    44.62692873032506
"""
    # A known header that failed before
    header_str_prob = """
NAXIS   =                    2 / number of array dimensions
WCSAXES =                    2 / Number of coordinate axes
CRPIX1  =               1024.5 / Pixel coordinate of reference point
CRPIX2  =               1024.5 / Pixel coordinate of reference point
CD1_1   = -1.7445934400771E-05 / Coordinate transformation matrix element
CD1_2   = -4.9826985362578E-08 / Coordinate transformation matrix element
CD2_1   = -5.0068838822312E-08 / Coordinate transformation matrix element
CD2_2   =  1.7530614610951E-05 / Coordinate transformation matrix element
CTYPE1  = 'RA---TAN'           / Right ascension, gnomonic projection
CTYPE2  = 'DEC--TAN'           / Declination, gnomonic projection
CRVAL1  =      5.8689341666667 / [deg] Coordinate value at reference point
CRVAL2  =     -71.995508583333 / [deg] Coordinate value at reference point
"""

    header_linear = fits.Header.fromstring(header_str_linear, sep='\n')
    header_sip = fits.Header.fromstring(header_str_sip, sep='\n')
    header_prob = fits.Header.fromstring(header_str_prob, sep='\n')

    true_wcs_linear = WCS(header_linear, relax=True)
    true_wcs_sip = WCS(header_sip, relax=True)
    true_wcs_prob = WCS(header_prob, relax=True)

    # Getting the pixel coordinates
    x, y = np.meshgrid(list(range(10)), list(range(10)))
    x = x.flatten()
    y = y.flatten()

    # Calculating the true sky positions
    world_pix_linear = true_wcs_linear.pixel_to_world(x, y)
    world_pix_sip = true_wcs_sip.pixel_to_world(x, y)
    world_pix_prob = true_wcs_prob.pixel_to_world(x, y)

    # Fitting the wcs, no distortion.
    fit_wcs_linear = fit_wcs_from_points((x, y),
                                         world_pix_linear,
                                         proj_point='center',
                                         sip_degree=None)

    # Fitting the wcs, with distortion.
    fit_wcs_sip = fit_wcs_from_points((x, y),
                                      world_pix_sip,
                                      proj_point='center',
                                      sip_degree=2)

    # Fitting the problematic WCS
    fit_wcs_prob = fit_wcs_from_points((x, y),
                                       world_pix_prob,
                                       proj_point='center',
                                       sip_degree=None)

    # Validate that the true sky coordinates calculated with `true_wcs_linear`
    # match sky coordinates calculated from the wcs fit with only linear terms

    world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y)

    dists = world_pix_linear.separation(world_pix_linear_new)

    assert dists.max() < 7e-5 * u.deg
    assert np.std(dists) < 2.5e-5 * u.deg

    # Validate that the true sky coordinates calculated with `true_wcs_sip`
    # match the sky coordinates calculated from the wcs fit with SIP of same
    # degree (2)

    world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y)
    dists = world_pix_sip.separation(world_pix_sip_new)

    assert dists.max() < 7e-6 * u.deg
    assert np.std(dists) < 2.5e-6 * u.deg

    # Validate that the true sky coordinates calculated from the problematic
    # WCS match

    world_pix_prob_new = fit_wcs_prob.pixel_to_world(x, y)
    dists = world_pix_prob.separation(world_pix_prob_new)

    assert dists.max() < 7e-6 * u.deg
    assert np.std(dists) < 2.5e-6 * u.deg

    # Test 360->0 degree crossover
    header_linear["CRVAL1"] = 352.3497414839765
    header_sip["CRVAL1"] = 352.3497414839765
    header_prob["CRVAL1"] = 352.3497414839765

    true_wcs_linear = WCS(header_linear, relax=True)
    true_wcs_sip = WCS(header_sip, relax=True)
    true_wcs_prob = WCS(header_prob)

    # Calculating the true sky positions
    world_pix_linear = true_wcs_linear.pixel_to_world(x, y)
    world_pix_sip = true_wcs_sip.pixel_to_world(x, y)
    world_pix_prob = true_wcs_prob.pixel_to_world(x, y)

    # Fitting the wcs, no distortion.
    fit_wcs_linear = fit_wcs_from_points((x, y),
                                         world_pix_linear,
                                         proj_point='center',
                                         sip_degree=None)

    # Fitting the wcs, with distortion.
    fit_wcs_sip = fit_wcs_from_points((x, y),
                                      world_pix_sip,
                                      proj_point='center',
                                      sip_degree=2)

    # Fitting the problem WCS
    fit_wcs_prob = fit_wcs_from_points((x, y),
                                       world_pix_prob,
                                       proj_point='center',
                                       sip_degree=None)

    # Validate that the true sky coordinates calculated with `true_wcs_linear`
    # match sky coordinates calculated from the wcs fit with only linear terms

    world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y)

    dists = world_pix_linear.separation(world_pix_linear_new)

    assert dists.max() < 7e-5 * u.deg
    assert np.std(dists) < 2.5e-5 * u.deg

    # Validate fit with SIP
    world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y)
    dists = world_pix_sip.separation(world_pix_sip_new)

    assert dists.max() < 7e-6 * u.deg
    assert np.std(dists) < 2.5e-6 * u.deg

    # Validate the problematic WCS
    world_pix_prob_new = fit_wcs_prob.pixel_to_world(x, y)
    dists = world_pix_prob.separation(world_pix_prob_new)

    assert dists.max() < 7e-6 * u.deg
    assert np.std(dists) < 2.5e-6 * u.deg

    # Test CRPIX bounds requirement
    wcs_str = """
WCSAXES =                    2 / Number of coordinate axes
CRPIX1  =               1045.0 / Pixel coordinate of reference point
CRPIX2  =               1001.0 / Pixel coordinate of reference point
PC1_1   =  0.00056205870415378 / Coordinate transformation matrix element
PC1_2   =    -0.00569181083243 / Coordinate transformation matrix element
PC2_1   =   0.0056776810932466 / Coordinate transformation matrix element
PC2_2   =   0.0004208048403273 / Coordinate transformation matrix element
CDELT1  =                  1.0 / [deg] Coordinate increment at reference point
CDELT2  =                  1.0 / [deg] Coordinate increment at reference point
CUNIT1  = 'deg'                / Units of coordinate increment and value
CUNIT2  = 'deg'                / Units of coordinate increment and value
CTYPE1  = 'RA---TAN'           / Right ascension, gnomonic projection
CTYPE2  = 'DEC--TAN'           / Declination, gnomonic projection
CRVAL1  =      104.57797893504 / [deg] Coordinate value at reference point
CRVAL2  =     -74.195502593322 / [deg] Coordinate value at reference point
LONPOLE =                180.0 / [deg] Native longitude of celestial pole
LATPOLE =     -74.195502593322 / [deg] Native latitude of celestial pole
TIMESYS = 'TDB'                / Time scale
TIMEUNIT= 'd'                  / Time units
DATEREF = '1858-11-17'         / ISO-8601 fiducial time
MJDREFI =                  0.0 / [d] MJD of fiducial time, integer part
MJDREFF =                  0.0 / [d] MJD of fiducial time, fractional part
DATE-OBS= '2019-03-27T03:30:13.832Z' / ISO-8601 time of observation
MJD-OBS =      58569.145993426 / [d] MJD of observation
MJD-OBS =      58569.145993426 / [d] MJD at start of observation
TSTART  =      1569.6467941661 / [d] Time elapsed since fiducial time at start
DATE-END= '2019-03-27T04:00:13.831Z' / ISO-8601 time at end of observation
MJD-END =      58569.166826748 / [d] MJD at end of observation
TSTOP   =      1569.6676274905 / [d] Time elapsed since fiducial time at end
TELAPSE =        0.02083332443 / [d] Elapsed time (start to stop)
TIMEDEL =    0.020833333333333 / [d] Time resolution
TIMEPIXR=                  0.5 / Reference position of timestamp in binned data
RADESYS = 'ICRS'               / Equatorial coordinate system
"""
    wcs_header = fits.Header.fromstring(wcs_str, sep='\n')
    ffi_wcs = WCS(wcs_header)

    yi, xi = (1000, 1000)
    y, x = (10, 200)

    center_coord = SkyCoord(ffi_wcs.all_pix2world([[xi + x // 2, yi + y // 2]],
                                                  0),
                            unit='deg')[0]
    ypix, xpix = [arr.flatten() for arr in np.mgrid[xi:xi + x, yi:yi + y]]
    world_pix = SkyCoord(*ffi_wcs.all_pix2world(xpix, ypix, 0), unit='deg')

    fit_wcs = fit_wcs_from_points((ypix, xpix), world_pix, proj_point='center')

    assert (fit_wcs.wcs.crpix.astype(int) == [1100, 1005]).all()
    assert fit_wcs.pixel_shape == (200, 10)
Пример #10
0
    def _fit_cutout_wcs(self, cutout_wcs, cutout_shape):
        """
        Given a full (including SIP coefficients) wcs for the cutout, 
        calculate the best fit linear wcs, and a measure of the goodness-of-fit.
        
        The new WCS is stored in ``self.cutout_wcs``.
        Goodness-of-fit measures are returned and stored in ``self.cutout_wcs_fit``.

        Parameters
        ----------
        cutout_wcs :  `~astropy.wcs.WCS`
            The full (including SIP coefficients) cutout WCS object 
        cutout_shape : tuple
            The shape of the cutout in the form (width, height).

        Returns
        -------
        response : tuple
            Goodness-of-fit statistics. (max dist, sigma)
        """

        # Getting matched pixel, world coordinate pairs
        # We will choose no more than 100 pixels spread evenly throughout the image
        # Centered on the center pixel.
        # To do this we the appropriate "step size" between pixel coordinates
        # (i.e. we take every ith pixel in each row/column) [TODOOOOOO]
        # For example in a 5x7 cutout with i = 2 we get:
        #
        # xxoxoxx
        # ooooooo
        # xxoxoxx
        # ooooooo
        # xxoxoxx
        #
        # Where x denotes the indexes that will be used in the fit.
        y, x = cutout_shape
        i = 1
        while (x / i) * (y / i) > 100:
            i += 1

        xvals = list(reversed(range(x // 2, -1, -i)))[:-1] + list(
            range(x // 2, x, i))
        if xvals[-1] != x - 1:
            xvals += [x - 1]
        if xvals[0] != 0:
            xvals = [0] + xvals

        yvals = list(reversed(range(y // 2, -1, -i)))[:-1] + list(
            range(y // 2, y, i))
        if yvals[-1] != y - 1:
            yvals += [y - 1]
        if yvals[0] != 0:
            yvals = [0] + yvals

        pix_inds = np.array(list(product(xvals, yvals)))
        world_pix = SkyCoord(cutout_wcs.all_pix2world(pix_inds, 0), unit='deg')

        # Getting the fit WCS
        linear_wcs = fit_wcs_from_points([pix_inds[:, 0], pix_inds[:, 1]],
                                         world_pix,
                                         proj_point='center')

        self.cutout_wcs = linear_wcs

        # Checking the fit (we want to use all of the pixels for this)
        pix_inds = np.array(
            list(
                product(list(range(cutout_shape[1])),
                        list(range(cutout_shape[0])))))
        world_pix = SkyCoord(cutout_wcs.all_pix2world(pix_inds, 0), unit='deg')
        world_pix_new = SkyCoord(linear_wcs.all_pix2world(pix_inds, 0),
                                 unit='deg')

        dists = world_pix.separation(world_pix_new).to('deg')
        sigma = np.sqrt(sum(dists.value**2))

        self.cutout_wcs_fit['WCS_MSEP'][0] = dists.max().value
        self.cutout_wcs_fit['WCS_SIG'][0] = sigma

        return (dists.max(), sigma)