Exemplo n.º 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)
Exemplo n.º 2
0
def recomputeXylsPixelPositions(originalXylsPath, originalWcsPath,
                                newWcsPathOrHeader):
    """
    Return pixel coordinates valid for `newWcsPathOrHeader` for
    the reference stars found in `originalXylsPath` (belonging to `originalWcsPath`).
    
    :rtype: tuple (x,y) with x and y being ndarrays
    """
    # Step 1: compute RA,Dec of reference stars (as this is not stored in .xyls)
    originalWCS = WCS(readHeader(originalWcsPath))
    x, y = readXy(originalXylsPath)
    ra, dec = originalWCS.all_pix2world(x, y, 0)

    # Step 2: compute pixel positions of reference stars in new WCS solution
    if isinstance(newWcsPathOrHeader, string_types):
        newWCS = WCS(readHeader(newWcsPathOrHeader))
    else:
        newWCS = WCS(newWcsPathOrHeader)

    # all_world2pix raised a NoConvergenc error
    # As we don't use SIP, we don't need to use all_world2pix.
    # wcs_world2pix doesn't support any distortion correction.
    xNew, yNew = newWCS.wcs_world2pix(ra, dec, 0)

    return xNew, yNew
Exemplo n.º 3
0
def pix2world(wcsHeader,
              width,
              height,
              startX=0,
              startY=0,
              corner=True,
              ascartesian=False):
    """
    Calculate RA, Dec coordinates of a given pixel coordinate rectangle.
           
    ra, dec = pix2world(..)
    ra and dec are indexed as [y,x]
    
    Each array element contains the RA,Dec coords of the top left corner of the
    given pixel if corner==True, otherwise the coords of the pixel center. 
    If corner==True, an additional row and column exists at the bottom and right so that
    it is possible to get the bottom and right corner values for those pixels.
    
    :param dictionary wcsHeader: WCS header
    :param width: width of rectangle
    :param height: height of rectangle
    :param startX: x coordinate of rectangle, can be negative
    :param startY: y coordinate of rectangle, can be negative
    
    If ascartesian=False:
    
    :rtype: tuple(ra, dec) with arrays of shape (height+1,width+1) if corner==True, else (height,width)
    
    If ascartesian=True:
    
    :rtype: array of shape (height[+1],width[+1],3) with x,y,z order 
    """
    if corner:
        startX -= 0.5  # top left corner instead of pixel center
        startY -= 0.5
    x, y = np.meshgrid(np.arange(startX, startX + width + corner),
                       np.arange(startY, startY + height + corner))

    # check if TAN projection and use our fast version, otherwise fall-back to astropy
    if wcsHeader['CTYPE1'] == 'RA---TAN' and wcsHeader['CTYPE2'] == 'DEC--TAN' and \
       wcsHeader['LATPOLE'] == 0.0:
        res = tan_pix2world(wcsHeader, x, y, 0, ascartesian=ascartesian)

    else:
        wcs = WCS(wcsHeader)
        ra, dec = wcs.all_pix2world(x, y, 0, ra_dec_order=True)
        if ascartesian:
            np.deg2rad(ra, ra)
            np.deg2rad(dec, dec)
            res = spherical_to_cartesian(None, dec, ra, astuple=False)
        else:
            res = ra, dec

    return res
Exemplo n.º 4
0
def pix2world(wcsHeader, width, height, startX=0, startY=0, corner=True, ascartesian=False):
    """
    Calculate RA, Dec coordinates of a given pixel coordinate rectangle.
           
    ra, dec = pix2world(..)
    ra and dec are indexed as [y,x]
    
    Each array element contains the RA,Dec coords of the top left corner of the
    given pixel if corner==True, otherwise the coords of the pixel center. 
    If corner==True, an additional row and column exists at the bottom and right so that
    it is possible to get the bottom and right corner values for those pixels.
    
    :param dictionary wcsHeader: WCS header
    :param width: width of rectangle
    :param height: height of rectangle
    :param startX: x coordinate of rectangle, can be negative
    :param startY: y coordinate of rectangle, can be negative
    
    If ascartesian=False:
    
    :rtype: tuple(ra, dec) with arrays of shape (height+1,width+1) if corner==True, else (height,width)
    
    If ascartesian=True:
    
    :rtype: array of shape (height[+1],width[+1],3) with x,y,z order 
    """
    if corner:
        startX -= 0.5 # top left corner instead of pixel center
        startY -= 0.5
    x, y = np.meshgrid(np.arange(startX,startX+width+corner), np.arange(startY,startY+height+corner))
    
    # check if TAN projection and use our fast version, otherwise fall-back to astropy
    if wcsHeader['CTYPE1'] == 'RA---TAN' and wcsHeader['CTYPE2'] == 'DEC--TAN' and \
       wcsHeader['LATPOLE'] == 0.0:
        res = tan_pix2world(wcsHeader, x, y, 0, ascartesian=ascartesian)
        
    else:
        wcs = WCS(wcsHeader)
        ra, dec = wcs.all_pix2world(x, y, 0, ra_dec_order=True)
        if ascartesian:
            np.deg2rad(ra, ra)
            np.deg2rad(dec, dec)
            res = spherical_to_cartesian(None, dec, ra, astuple=False)
        else:
            res = ra, dec
    
    return res
Exemplo n.º 5
0
Arquivo: fits.py Projeto: esa/auromat
def recomputeXylsPixelPositions(originalXylsPath, originalWcsPath, newWcsPathOrHeader):
    """
    Return pixel coordinates valid for `newWcsPathOrHeader` for
    the reference stars found in `originalXylsPath` (belonging to `originalWcsPath`).
    
    :rtype: tuple (x,y) with x and y being ndarrays
    """
    # Step 1: compute RA,Dec of reference stars (as this is not stored in .xyls)
    originalWCS = WCS(readHeader(originalWcsPath))
    x, y = readXy(originalXylsPath)
    ra, dec = originalWCS.all_pix2world(x, y, 0)
    
    # Step 2: compute pixel positions of reference stars in new WCS solution
    if isinstance(newWcsPathOrHeader, string_types):
        newWCS = WCS(readHeader(newWcsPathOrHeader))
    else:
        newWCS = WCS(newWcsPathOrHeader)

    # all_world2pix raised a NoConvergenc error
    # As we don't use SIP, we don't need to use all_world2pix.
    # wcs_world2pix doesn't support any distortion correction. 
    xNew, yNew = newWCS.wcs_world2pix(ra, dec, 0)
    
    return xNew,yNew
Exemplo n.º 6
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)