Exemplo n.º 1
0
def combine_fitsheader(headers, cdelt=None, pa=None):
    """
    Returns a FITS header which encompasses all input headers.
    """

    if not isinstance(headers, (list, tuple)):
        header = (headers, )

    if len(headers) == 1 and cdelt is None and pa is None:
        return headers[0]

    crval = barycenter_lonlat([h['CRVAL1'] for h in headers],
                              [h['CRVAL2'] for h in headers])

    if cdelt is None or pa is None:
        cdeltpa = [get_cdelt_pa(h) for h in headers]

    if cdelt is None:
        cdelt = min([np.min(abs(cdelt)) for cdelt, pa in cdeltpa])

    if pa is None:
        pa = tmf.mean_degrees(np.array([pa for cdelt, pa in cdeltpa]))

    header0 = create_fitsheader((1, 1),
                                cdelt=cdelt,
                                pa=pa,
                                crpix=(1, 1),
                                crval=crval)

    proj0 = wcs.Projection(header0)
    xy0 = []
    for h in headers:
        proj = wcs.Projection(h)
        nx = h['NAXIS1']
        ny = h['NAXIS2']
        x = h['CRPIX1']
        y = h['CRPIX2']
        edges = proj.toworld(
            ([0.5, x, nx + 0.5, 0.5, x, nx + 0.5, 0.5, x, nx + 0.5],
             [0.5, 0.5, 0.5, y, y, y, ny + 0.5, ny + 0.5, ny + 0.5]))
        xy0.append(proj0.topixel(edges))

    xmin0 = np.round(min([min(c[0]) for c in xy0]))
    xmax0 = np.round(max([max(c[0]) for c in xy0]))
    ymin0 = np.round(min([min(c[1]) for c in xy0]))
    ymax0 = np.round(max([max(c[1]) for c in xy0]))

    header0['NAXIS1'] = int(xmax0 - xmin0 + 1)
    header0['NAXIS2'] = int(ymax0 - ymin0 + 1)
    header0['CRPIX1'] = 2 - xmin0
    header0['CRPIX2'] = 2 - ymin0

    return header0
Exemplo n.º 2
0
def area_within_reg(reg_name, base_fits=m31):
    '''
    returns deg^s 
    deg^2 to arcsec^2: areas*3600.*3600.
    deg^2 to arcmin^2: areas*3600.
    '''
    # finds area of concentric reg shapes
    # use GenUtils.area for the area of a polygon.
    tot_areas, areas = [], []
    proj = wcs.Projection(f_header)
    r = pyregion.open(reg_name).as_imagecoord(header=f_header)
    patch_list, artist_list = r.get_mpl_patches_texts()
    for p in patch_list[::-1]:
        verts_xy = p.get_xy()
        pixels = (verts_xy[:, 0], verts_xy[:, 1])
        ra_v, dec_v = proj.toworld(pixels)
        verts = np.column_stack((ra_v, dec_v))
        tot_areas.append(area(verts))

    for i in range(len(tot_areas)):
        if i == len(tot_areas) - 1:
            areas.append(tot_areas[i])
        else:
            areas.append(tot_areas[i] - tot_areas[i + 1])

    # deg^2 to arcsec^2: areas*3600.*3600.
    # deg^2 to arcmin^2: areas*3600.
    return np.array(areas)
Exemplo n.º 3
0
    def loadFromFITS(self, inputFITS):
        """
        load a FITS histogram file
        
        Arguments:
        - `inputfits`: filename or fits HDU
        """

        if (type(inputFITS) == str):
            hdu = pyfits.open(inputFITS).pop(0)
        else:
            hdu = inputFITS

        self.hist = hdu.data.transpose()
        self._bins = self.hist.shape

        proj = wcs.Projection(hdu.header)
        ndim = len(self._bins)

        edges = []
        self._range = []
        axisnames = []
        self._ctypes = []

        for dim in xrange(ndim):
            # note that histogramdd returns edges for 0-N+1 (including
            # the lower edge of the non-existant next bin), so we do
            # the same here to keep things the same
            a = np.zeros((self._bins[dim] + 1, ndim))
            a[:, dim] = np.arange(self._bins[dim] + 1) + 0.5
            edges.append(proj.toworld(a)[:, dim])
            self._range.append((edges[dim][0], edges[dim][-1]))
            self._ctypes.append(hdu.header["CTYPE%d" % (dim + 1)])
            if (hdu.header.get("CNAME%d" % (dim + 1))):
                axisnames.append(hdu.header["CNAME%d" % (dim + 1)])
            else:
                axisnames.append(self._ctypes[dim][0:4])

        self.axisNames = np.array(axisnames)

        self._binLowerEdges = edges
        self._range = np.array(self._range)

        if (hdu.header.get("BSCALE")):
            self.valueScale = hdu.header["BSCALE"]

        if (hdu.header.get("BSCALE")):
            self.valueZero = hdu.header["BZERO"]

        if (hdu.header.get("NSAMP")):
            self._numsamples += int(hdu.header["NSAMP"])
Exemplo n.º 4
0
    def __init__(self, wcs, **keywords):
        """
        wcs : FITS header or Kapteyn wcs.Projection instance
            Representation of the world coordinate system

        """
        import kapteyn.wcs as kwcs
        if isinstance(wcs, pyfits.Header):
            wcs = kwcs.Projection(wcs)
        if 'dtype' not in keywords:
            keywords['dtype'] = float
        wcs.allow_invalid = True
        Operator.__init__(self, **keywords)
        self.wcs = wcs
Exemplo n.º 5
0
    def load_header(self, header, fobj=None):
        # For kapteyn, header just needs to be duck-typed like a dict
        self.header = {}
        self.header.update(header.items())

        self.fix_bad_headers()

        try:
            self.wcs = kapwcs.Projection(self.header, skyout=self._skyout)

            self.coordsys = choose_coord_system(self.header)

        except Exception as e:
            self.logger.error("Error making WCS object: %s" % (str(e)))
            self.wcs = None
Exemplo n.º 6
0
def points_inside_reg(pyfits_obj, reg_name, ra_points, dec_points, plot=False):
    '''
    Takes an open fits file (pyfits_obj), a reg file (reg_name), ra and dec
    array, and returns the indices of the ra dec array inside each shape in
    the region file. Will also plot...
    inds - cumulative
    '''
    if plot == True:
        ax = pywcsgrid2.subplot(111, header=pyfits_obj[0].header)
        ax.grid()
        ax.imshow(pyfits_obj[0].data, cmap=cm.gray, origin="lower")

    # load projection, reg shapes, and get them in python
    proj = wcs.Projection(pyfits_obj[0].header)
    r = pyregion.open(reg_name).as_imagecoord(header=pyfits_obj[0].header)
    patch_list, artist_list = r.get_mpl_patches_texts()

    radec = np.column_stack((ra_points, dec_points))
    # get masks of ra,dec in each shape
    masks = []
    for p in patch_list[::-1]:
        if plot == True: ax.add_patch(p)
        verts_xy = p.get_xy()
        pixels = (verts_xy[:, 0], verts_xy[:, 1])
        ra_v, dec_v = proj.toworld(pixels)
        verts = np.column_stack((ra_v, dec_v))
        masks.append(nxutils.points_inside_poly(radec, verts))

    # subtract masks from outside to inside to not over count.
    inds = []
    for i in range(len(masks) - 1):
        isolated_mask = (masks[i] - masks[i + 1])
        if len(isolated_mask) > 0:
            within = np.nonzero(isolated_mask)[0]
            inds.append(within)
            if plot == True:
                ax["fk5"].plot(ra_points[within],
                               dec_points[within],
                               '.',
                               alpha=0.2,
                               label='%i' % i,
                               color=cols[i])
                for t in artist_list:
                    ax.add_artist(t)
                ax.add_compass(loc=1)
                ax.legend()
    return inds
Exemplo n.º 7
0
    def load_header(self, header, fobj=None):
        # For kapteyn, header just needs to be duck-typed like a dict
        self.header = {}
        self.header.update(header.items())

        self.fix_bad_headers()

        try:
            self.logger.debug("Trying to make kapteyn wcs object")
            self.wcs = kapwcs.Projection(self.header, skyout=self._skyout)

            self.coordsys = get_coord_system_name(self.header)
            self.logger.debug("Coordinate system is: %s" % (self.coordsys))

        except Exception as e:
            self.logger.error("Error making WCS object: %s" % (str(e)))
            self.wcs = None
Exemplo n.º 8
0
"""Fit gamma-ray images with Sherpa."""
import sherpa.astro.ui as ui
from kapteyn import wcs, positions
try:
    from astropy.io import fits
except:
    import pyfits as fits

filename = 'skymap_ex.fits'
nomposstr = '05h34m31.94s 22d00m52.2s'
header = fits.getheader(filename)
proj = wcs.Projection(header)
xc, yc = float(header['NAXIS1']) / 2., float(header['NAXIS2']) / 2.
ui.load_image(filename)
ui.notice2d('circle({0}, {1}, {2})'.format(xc, yc,
                                           float(header['NAXIS2']) / 4.))
ui.set_source(ui.gauss2d.g1 + ui.gauss2d.g2)
g1.xpos = xc
g1.ypos = yc
g2.fwhm = g1.fwhm = 3.
ui.link(g2.xpos, g1.xpos)
ui.link(g2.ypos, g1.ypos)
g2.ampl = 50.
g1.ampl = 50.
ui.guess()
ui.fit()
ui.image_fit()
ui.covar()
conf = ui.get_covar_results()
conf_dict = dict([(n, (v, l, h)) for n, v, l, h in zip(
    conf.parnames, conf.parvals, conf.parmins, conf.parmaxes)])
distortion_corrected_header = raw_header.copy()

import global_PC_distort

transformed_crpix = global_PC_distort.transform_to_global_pixel_coords(
    0, raw_CRPIX1, raw_CRPIX2)
#transformed_crpix = global_PC_distort.transform_to_global_pixel_coords(0, raw_CRPIX1,raw_CRPIX2, 0.28*180/math.pi )

distortion_corrected_header["CRPIX1"] = transformed_crpix[0]
distortion_corrected_header["CRPIX2"] = transformed_crpix[1]

print "Raw crpix1", raw_header["CRPIX1"]
print "corrected crpix1", distortion_corrected_header["CRPIX1"]

#now load it as a pixel / WCS transformation
distortion_corrected_map = (wcs.Projection(distortion_corrected_header)).sub(
    nsub=2)

##########################################################################

#Chip to chip adjustments are approximate alterations to the Holtzman 1995 solution as determined by eye, by comparison with drizzled mosaics from HLA in 2010
#NB the HLA mosaics presumably use the Anderson 2003 solution, hence the discrepancy.
#Ideally the distortion correction should be rewritten to match Anderson's, but this is a stop gap measure that produces aesthetically pleasing (And presumably, approximately correct) plots.

WF_to_PC_pix = 2.187  #approximate pixel size ratio

#chip_adjustments_x=[0,  0, 0, 0]
#chip_adjustments_y=[0,  0, 0, 0]

chip_adjustments_x = [0, 0.6 * WF_to_PC_pix, 1.3 * WF_to_PC_pix, 0]
chip_adjustments_y = [
Exemplo n.º 10
0
def get_img_WCS_map(fits_filename):
    hdulist = pyfits.open(fits_filename)
    header = hdulist[0].header
    proj = wcs.Projection(header)
    return proj.sub(nsub=2)
Exemplo n.º 11
0
    minorCoordOriginsArray[i,0] = minorCoordArray[i,0] - \
        minorPosOffset * math.sin(math.radians(minorPA))

    minorCoordTipsArray[i,0] = minorCoordArray[i,0] + \
        minorPosOffset * math.sin(math.radians(minorPA))

for i in xrange(0, minorCoordArray.shape[0]):
    minorCoordOriginsArray[i,1] = minorCoordArray[i,1] - \
        minorPosOffset * math.cos(math.radians(minorPA))

    minorCoordTipsArray[i,1] = minorCoordArray[i,1] + \
        minorPosOffset * math.cos(math.radians(minorPA))

# Extract pixel coordinates from wcs coordinates
# Define header for calculations
proj1 = kwcs.Projection(hmom0)
# extract coordinate information of extra axes
extraCoords = proj1.toworld((1., 1., 1.))


def arrowHead(image, x, y, dx, dy, head='origin'):
    theta = math.atan2(-dy, -dx)
    # make body
    image.arrow(x, y, dx, dy)
    # Make head
    barb = 10
    phi = math.radians(10)
    if head == 'origin':
        rho = theta + phi
    else:
        rho = math.atan2(dy, dx) + phi
Exemplo n.º 12
0
def FITS_to_HPX(header, data, Nside, return_sparse=False):
    """Convert data from FITS format to sparse HPX grid

    Parameters
    ----------
    header : dict or PyFITS header
        WCS header describing the coordinates of the input array
    data : array_like
        Input data array
    Nside : int
        HEALPix gridding parameter

    Returns
    -------
    hpx_data : csr matrix
        The HPX-projected data
    """
    # Here's what we do for this function: we're working in "IMG coords"
    # (i.e. the projection of the input data) and "HPX coords" (i.e. the
    # projection of the output data).  In between, we use "WCS coords".
    #
    # These are the steps involved:
    #  1. Create an array of image edge-pixels in IMG coords, and project
    #     these to HPX coords.
    #  2. From these bounds, create a regular grid of HPX coords that covers
    #     the image.  Project this grid to IMG coords.
    #  3. In IMG coords, interpolate the image data to the healpix grid.
    #  4. Use this data to construct a sparse array in HPX coords.

    if header['NAXIS'] != 2:
        raise ValueError("input data & header must be two dimensional")

    if data.shape != (header['NAXIS2'], header['NAXIS1']):
        raise ValueError("data shape must match header metadata")

    # Create wcs projection instance from the header
    proj_img = wcs.Projection(header)

    # Create wcs projection for healpix grid
    # Note that the "pixel" coordinates here are measured in degrees...
    # 0 to 360 in x/RA and -90 to 90 in y/DEC
    proj_hpx = wcs.Projection({
        'NAXIS': 2,
        'CTYPE1': 'RA---HPX',
        'CTYPE2': 'DEC--HPX'
    })

    # Define the dimension of the HEALPIX SciDB grid
    Nx_hpx, Ny_hpx = HPX_grid_size(Nside)
    dx_hpx = dy_hpx = HPX_grid_step(Nside)

    #x_hpx = np.linspace(0, 360, Nx_hpx, endpoint=False)
    #y_hpx = np.linspace(-90, 90, Ny_hpx)

    # Find the coordinates of the pixels at the edge of the image
    # Projecting these onto the healpix grid will give the bounds we need.
    img_bounds_x = np.arange(header['NAXIS2'])
    zeros_x = np.zeros_like(img_bounds_x)
    img_bounds_y = np.arange(header['NAXIS1'])
    zeros_y = np.zeros_like(img_bounds_y)

    img_bounds_pix = np.concatenate([
        img_bounds_x, img_bounds_x, zeros_y, zeros_y + img_bounds_x[-1],
        zeros_x, zeros_x + img_bounds_y[-1], img_bounds_y, img_bounds_y
    ]).reshape((2, -1)).T

    x_bound_hpx, y_bound_hpx =\
                    proj_hpx.topixel(proj_img.toworld(img_bounds_pix)).T

    # here we take the pixels at the edge of the boundaries of the image,
    # transform them to HPX coordinates, and find the required extent
    # of the HPX pixel grid.
    #    [TODO: check for crossing the pole]
    # first we need to calculate pixel number
    i_bound_hpx = x_bound_hpx / dx_hpx
    j_bound_hpx = (y_bound_hpx + 90.) / dy_hpx

    i_hpx = np.arange(int(np.floor(i_bound_hpx.min())),
                      int(np.ceil(i_bound_hpx.max()) + 1))
    j_hpx = np.arange(int(np.floor(j_bound_hpx.min())),
                      int(np.ceil(j_bound_hpx.max()) + 1))

    x_hpx = i_hpx * dx_hpx
    y_hpx = j_hpx * dy_hpx - 90.

    # Create the grid of HPX pixels
    pixel_ind_hpx = np.vstack(map(np.ravel, np.meshgrid(i_hpx, j_hpx))).T
    pixel_locs_hpx = np.vstack(map(np.ravel, np.meshgrid(x_hpx, y_hpx))).T
    pixel_locs_img = proj_img.topixel(proj_hpx.toworld(pixel_locs_hpx))

    ## DEBUG: Plot the borders & grid in the HPX projection
    #import matplotlib.pyplot as plt
    #plt.plot(i_bound_hpx, j_bound_hpx, '.k')
    #plt.plot(pixel_ind_hpx[:, 0], pixel_ind_hpx[:, 1], '.r')
    #plt.show()
    #exit()

    ## DEBUG: Plot the HPX grid in the IMG projection
    #import matplotlib.pyplot as plt
    #plt.plot(img_bounds_pix[:, 0], img_bounds_pix[:, 1], '.k')
    #plt.plot(pixel_locs_img[:, 0], pixel_locs_img[:, 1], '.r')
    #plt.show()
    #exit()

    # Interpolate from data to pixel locations
    I = GridInterpolation(data, [0, 0], [1, 1])
    HPX_vals = I(pixel_locs_img)  #.reshape(len(y_hpx), len(x_hpx))

    # # DEBUG: Plot regridded input data next to the interpolated HPX data
    # import matplotlib.pyplot as plt
    # plt.figure(figsize=(8, 8))
    # plt.subplot(211, aspect='equal')
    # plt.contourf(x_hpx, y_hpx, HPX_vals)
    # plt.subplot(212, aspect='equal')
    # plt.contourf(regrid(data, 5))
    # plt.show()
    # exit()

    good_vals = ~np.isnan(HPX_vals)
    x, y = pixel_ind_hpx[good_vals].T
    HPX_vals = HPX_vals[good_vals]

    if return_sparse:
        return sparse.coo_matrix((HPX_vals, (x, y)), shape=(Nx_hpx, Ny_hpx))
    else:
        output = np.zeros(len(HPX_vals),
                          dtype=[('time', np.int64), ('x', np.int64),
                                 ('y', np.int64), ('val', np.float64)])
        # use MJD in seconds
        output['time'] = int(header['TAI'] * 24 * 60 * 60)
        output['x'] = x
        output['y'] = y
        output['val'] = HPX_vals
        return output
Exemplo n.º 13
0
def XY2radec(pyfits_obj, x, y):
    # returns ra,dec based on (an already opened) fits image.
    proj = wcs.Projection(pyfits_obj[0].header)
    pixels = (x, y)
    return proj.toworld(pixels)
Exemplo n.º 14
0
m31 = '/Users/Phil/research/PHAT/m31_fullfield.fits'

# MAC
data_src = '/Users/Phil/research/PHAT/Data/'
base_fits = '/Users/Phil/research/PHAT/Data/12058_M31-B01-F10-UVIS_F336W_drz.chip1.fits'

# astro network
data_src = '/astro/net/angst2/philrose/PHAT/FullBricks/'
base_fits = '/astro/net/angst2/philrose/PHAT/Fields/drzs/12058_M31-B01-F10-UVIS_F336W_drz.chip1.fits'

print 'fits are centered with', base_fits
f = pyfits.open(base_fits)
f_shape = (f[0].header["NAXIS1"], f[0].header["NAXIS2"])
f_data = f[0].data
f_proj = wcs.Projection(f[0].header)
f_header = f[0].header
f.close()


def read_basefits():
    return f


def radec_to_reg(ra,
                 dec,
                 outfile='radec.reg',
                 shape='circle',
                 size=0.5,
                 header='default'):
    if header == 'default':
Exemplo n.º 15
0
        kvdict['demin'] = float(kvdict['demin'])
    except:
        print('Provide lower declination demin')
        raise (BaseException)

try:
    getkey(kvdict, 'outfile')
except:
    print('Provide output file outfile')
    raise (BaseException)

# Open hdu
hduc = fits.open(kvdict['infile'])[0]
w = wcs.WCS(hduc.header, naxis=2)
hdu = read2dim(hduc, 0)
proj = kapwcs.Projection(hdu.header)
proj.skyout = (kapwcs.equatorial, kapwcs.fk5, 'J2000')

if 'tempfile' in kvdict.keys():
    # Get info
    hduinfoc = fits.open(kvdict['tempfile'])[0]

    # This makes the whole thing slightly unprecise. Write into the doc that it's always the first plane as a reference plane
    hduinfo = read2dim(hduinfoc, 0)
    nypsinfo = hduinfo.shape[-2]
    nxpsinfo = hduinfo.shape[-1]
    #wnew = wcs.WCS(hduinfo.header, naxis=2)
    #solution = wnew.wcs_pix2world(nxps,nyps,0)
    projinfo = kapwcs.Projection(hduinfo.header)
    projinfo.skyout = (kapwcs.equatorial, kapwcs.fk5, 'J2000')
    pixelinfo = ([1, nxpsinfo], [1, nypsinfo])
Exemplo n.º 16
0
Vr = header_gds['VELR']
fr = header_gds['CRVAL1']
df = header_gds['CDELT1']
crpix = header_gds['CRPIX1']
c = wcs.c  # Speed of light
p = pixrange = arange(crpix - 2, crpix + 3)  # Range of pixels for which we
# want world coordinates
# Calculate the barycentric equivalents
fb = f0 * (1.0 - Vr / c)
Vtopo = c * ((fb * fb - fr * fr) / (fb * fb + fr * fr))
dfb = df * (c - Vtopo) / sqrt(c * c - Vtopo * Vtopo)
print("Topocentric correction (km/s):", Vtopo / 1000)
print("Barycentric frequency and increment (Hz):", fb, dfb)

# VRAD from spectral translation, assumed to give the correct velocities
proj = wcs.Projection(header_gds)
spec = proj.spectra(ctype='VRAD')
V1 = spec.toworld1d(pixrange)

# Radio velocities with GIPSY formula with barycentric
# values (excact).
V2 = Vr - c * (p - crpix) * dfb / f0

# Radio velocities with GIPSY formula without rest frequency and
# with barycentric values (exact).
V3 = Vr + (p - crpix) * dfb * (Vr - c) / fb

# Radio velocities with GIPSY formula using topocentric,
# values (approximation).
V4 = Vr - c * (p - crpix) * df / f0
Exemplo n.º 17
0
            if opts.juldate is None: del(c[s])
            else: ephem.Body.compute(c[s], date)


srcs,coff,catalogs = a.scripting.parse_srcs(opts.src,opts.cat)
cat = a.src.get_catalog(srcs=srcs,catalogs=catalogs)
update_pos(cat)



for file in args:
    print file
    hdulist = pf.open(file)
    hdr = hdulist[0].header
    width = n.abs(opts.width/hdulist[0].header.get('CDELT1'))
    proj = wcs.Projection(hdulist[0].header)
    img_ra = hdulist[0].header.get('CRVAL1')*a.img.deg2rad
    img_dec = hdulist[0].header.get('CRVAL2')*a.img.deg2rad
    center = a.phs.RadioFixedBody(img_ra,
            img_dec)
    ephem.FixedBody.compute(center,ephem.J2000)
    for name,src in cat.iteritems():
        src_sep = ephem.separation(src,center)
        if src_sep<opts.sep:
            if opts.verb: print "getting \n",src
            ra = src.ra * a.img.rad2deg
            dec = src.dec * a.img.rad2deg
            if opts.verb:print src_sep,ra,dec
            px = n.round(proj.topixel((ra,dec,1,1)))
            if opts.verb:print "at",px
#            if opts.verb:print "subimg"
Exemplo n.º 18
0
cdelt  = (-1.5, 3)
pa = -25.
header = create_fitsheader((10,10), cdelt=cdelt, pa=pa)
cdelt_, pa_ = wu.get_cdelt_pa(header)
if any_neq(cdelt, cdelt_): raise TestFailure()
if any_neq(pa, pa_): raise TestFailure()

# combine_fitsheader
headers = [
    wu.create_fitsheader((1,1), cdelt=3., crval=(0,0)),
    wu.create_fitsheader((3,3), cdelt=1., crval=(1,1)),
    wu.create_fitsheader((5,5), cdelt=1., crval=(3,3)),
    wu.create_fitsheader((2,2), cdelt=1., crval=(5,5)),
]
header0 = wu.combine_fitsheader(headers)
proj0 = wcs.Projection(header0)

for iheader, header in enumerate(headers):
    nx = header['NAXIS1']
    ny = header['NAXIS2']
    x = header['CRPIX1']
    y = header['CRPIX2']
    edges = (np.array(3*(0.5,x,nx+0.5)), np.array((0.5,0.5,0.5,y,y,y,ny+0.5,ny+0.5,ny+0.5)))

    a,d = wcs.Projection(header).toworld(edges)
    x0,y0 = proj0.topixel((a,d))

    epsilon = 1.e-10
    if np.any(x0 < 0.5-epsilon) or np.any(y0 < 0.5-epsilon): raise TestFailure()
    if np.any(x0 > header0['NAXIS1'] + 0.5 + epsilon): raise TestFailure()
    if np.any(y0 > header0['NAXIS2'] + 0.5 + epsilon): raise TestFailure()