Beispiel #1
0
def norm_dist(src1, src2):
    """
    Calculate the normalised distance between two sources.
    Sources are elliptical Gaussians.

    The normalised distance is calculated as the GCD distance between the centers,
    divided by quadrature sum of the radius of each ellipse along a line joining the two ellipses.

    For ellipses that touch at a single point, the normalized distance will be 1/sqrt(2).

    Parameters
    ----------
    src1, src2 : object
        The two positions to compare. Objects must have the following parameters: (ra, dec, a, b, pa).

    Returns
    -------
    dist: float
        The normalised distance.

    """
    if src1 == src2:
        return 0
    dist = gcd(src1.ra, src1.dec, src2.ra, src2.dec)  # degrees

    # the angle between the ellipse centers
    phi = bear(src1.ra, src1.dec, src2.ra, src2.dec)  # Degrees
    # Calculate the radius of each ellipse along a line that joins their centers.
    r1 = src1.a * src1.b / np.hypot(src1.a * np.sin(np.radians(phi - src1.pa)),
                                    src1.b * np.cos(np.radians(phi - src1.pa)))
    r2 = src2.a * src2.b / np.hypot(
        src2.a * np.sin(np.radians(180 + phi - src2.pa)),
        src2.b * np.cos(np.radians(180 + phi - src2.pa)))
    R = dist / (np.hypot(r1, r2) / 3600)
    return R
Beispiel #2
0
 def pix2sky_vec(self, pixel, r, theta):
     """
     Convert a vector from pixel to sky coords
     vector is calculated at an origin pixel=(x,y)
     and has a magnitude (r) [in pixels]
     and an angle (theta) [in degrees]
     input:
         pixel - (x,y) of origin
         r - magnitude in pixels
         theta - in degrees
     return:
     ra,dec - corresponding to pixels x,y
     r,pa - magnitude and angle (degrees) of the original vector, as measured on the sky
     """
     ra1, dec1 = self.pix2sky(pixel)
     x, y = pixel
     a = [
         x + r * np.cos(np.radians(theta)),
         y + r * np.sin(np.radians(theta))
     ]
     locations = self.pix2sky(a)
     ra2, dec2 = locations
     a = gcd(ra1, dec1, ra2, dec2)
     pa = bear(ra1, dec1, ra2, dec2)
     return ra1, dec1, a, pa
Beispiel #3
0
    def pix2sky_ellipse(self, pixel, sx, sy, theta):
        """
        Convert an ellipse from pixel to sky coords
        sx/sy vectors are calculated at an origin pos=(x,y)
        Input parameters are:
        x,y - the x,y pixels corresponding to the ra/dec position
        sx, sy - the major minor axes (FWHM) in pixels
        theta - the position angle in degrees
        Output params are all in degrees

        :param pixel: [x,y] of the ellipse center
        :param sx: major axis
        :param sy: minor axis
        :param theta: position angle
        :return: ra, dec, a, b, pa
        """
        ra, dec = self.pix2sky(pixel)
        x, y = pixel
        v_sx = [
            x + sx * np.cos(np.radians(theta)),
            y + sx * np.sin(np.radians(theta))
        ]
        ra2, dec2 = self.pix2sky(v_sx)
        major = gcd(ra, dec, ra2, dec2)
        pa = bear(ra, dec, ra2, dec2)

        v_sy = [
            x + sy * np.cos(np.radians(theta - 90)),
            y + sy * np.sin(np.radians(theta - 90))
        ]
        ra2, dec2 = self.pix2sky(v_sy)
        minor = gcd(ra, dec, ra2, dec2)
        pa2 = bear(ra, dec, ra2, dec2) - 90

        # The a/b vectors are perpendicular in sky space, but not always in pixel space
        # so we have to account for this by calculating the angle between the two vectors
        # and modifying the minor axis length
        defect = pa - pa2
        minor *= abs(np.cos(np.radians(defect)))
        return ra, dec, major, minor, pa
Beispiel #4
0
    def pix2sky_ellipse(self, pixel, sx, sy, theta):
        """
        Convert an ellipse from pixel to sky coords
        sx/sy vectors are calculated at an origin pos=(x,y)
        Input parameters are:
        x,y - the x,y pixels corresponding to the ra/dec position
        sx, sy - the major minor axes (FWHM) in pixels
        theta - the position angle in degrees
        Output params are all in degrees

        :param pixel: [x,y] of the ellipse center
        :param sx: major axis
        :param sy: minor axis
        :param theta: position angle
        :return: ra, dec, a, b, pa
        """
        ra, dec = self.pix2sky(pixel)
        x, y = pixel
        v_sx = [x + sx * np.cos(np.radians(theta)),
                y + sx * np.sin(np.radians(theta))]
        ra2, dec2 = self.pix2sky(v_sx)
        major = gcd(ra, dec, ra2, dec2)
        pa = bear(ra, dec, ra2, dec2)

        v_sy = [x + sy * np.cos(np.radians(theta-90)),
                y + sy * np.sin(np.radians(theta-90))]
        ra2, dec2 = self.pix2sky(v_sy)
        minor = gcd(ra, dec, ra2, dec2)
        pa2 = bear(ra, dec, ra2, dec2) - 90

        # The a/b vectors are perpendicular in sky space, but not always in pixel space
        # so we have to account for this by calculating the angle between the two vectors
        # and modifying the minor axis length
        defect = pa - pa2
        minor *= abs(np.cos(np.radians(defect)))
        return ra, dec, major, minor, pa
Beispiel #5
0
def norm_dist(src1,src2):
    """
    Calculate the normalised distance between two sources.
    Sources are elliptical gaussians.
    :param src1:
    :param src2:
    :return:
    """
    if src1 == src2:
        return 0
    dist = gcd(src1.ra, src1.dec, src2.ra, src2.dec) # degrees

    # the angle between the ellipse centers
    phi = bear(src1.ra, src1.dec, src2.ra, src2.dec) # Degrees
    # Calculate the radius of each ellpise along a line that joins their centers.
    r1 = src1.a*src1.b / np.hypot(src1.a * np.sin(np.radians(phi - src1.pa)),
                                  src1.b * np.cos(np.radians(phi - src1.pa)))
    r2 = src2.a*src2.b / np.hypot(src2.a * np.sin(np.radians(180 + phi - src2.pa)),
                                  src2.b * np.cos(np.radians(180 + phi - src2.pa)))
    R = dist / (np.hypot(r1,r2) / 3600)
    return R
Beispiel #6
0
def norm_dist(src1, src2):
    """
    Calculate the normalised distance between two sources.
    Sources are elliptical gaussians.
    :param src1:
    :param src2:
    :return:
    """
    if src1 == src2:
        return 0
    dist = gcd(src1.ra, src1.dec, src2.ra, src2.dec)  # degrees

    # the angle between the ellipse centers
    phi = bear(src1.ra, src1.dec, src2.ra, src2.dec)  # Degrees
    # Calculate the radius of each ellpise along a line that joins their centers.
    r1 = src1.a * src1.b / np.hypot(src1.a * np.sin(np.radians(phi - src1.pa)),
                                    src1.b * np.cos(np.radians(phi - src1.pa)))
    r2 = src2.a * src2.b / np.hypot(
        src2.a * np.sin(np.radians(180 + phi - src2.pa)),
        src2.b * np.cos(np.radians(180 + phi - src2.pa)))
    R = dist / (np.hypot(r1, r2) / 3600)
    return R
Beispiel #7
0
 def pix2sky_vec(self, pixel, r, theta):
     """
     Convert a vector from pixel to sky coords
     vector is calculated at an origin pixel=(x,y)
     and has a magnitude (r) [in pixels]
     and an angle (theta) [in degrees]
     input:
         pixel - (x,y) of origin
         r - magnitude in pixels
         theta - in degrees
     return:
     ra,dec - corresponding to pixels x,y
     r,pa - magnitude and angle (degrees) of the original vector, as measured on the sky
     """
     ra1, dec1 = self.pix2sky(pixel)
     x, y = pixel
     a = [x + r * np.cos(np.radians(theta)),
          y + r * np.sin(np.radians(theta))]
     locations = self.pix2sky(a)
     ra2, dec2 = locations
     a = gcd(ra1, dec1, ra2, dec2)
     pa = bear(ra1, dec1, ra2, dec2)
     return ra1, dec1, a, pa
Beispiel #8
0
def errors(source, model, wcshelper):
    """
    Convert pixel based errors into sky coord errors
    :param source: Source object
    :param wcshelper: WCSHelper object
    :return:
    """

    # if the source wasn't fit then all errors are -1
    if source.flags & (flags.NOTFIT | flags.FITERR):
        source.err_peak_flux = source.err_a = source.err_b = source.err_pa = -1
        source.err_ra = source.err_dec = source.err_int_flux = -1
        return source
    # copy the errors from the model
    prefix = "c{0}_".format(source.source)
    err_amp = model[prefix+'amp'].stderr
    xo,yo = model[prefix+'xo'].value, model[prefix+'yo'].value
    err_xo = model[prefix+'xo'].stderr
    err_yo = model[prefix+'yo'].stderr

    sx, sy = model[prefix+'sx'].value, model[prefix+'sy'].value
    err_sx = model[prefix+'sx'].stderr
    err_sy = model[prefix+'sy'].stderr

    theta = model[prefix+'theta'].value
    err_theta = model[prefix+'theta'].stderr

    source.err_peak_flux = err_amp
    pix_errs = [err_xo,err_yo,err_sx,err_sy,err_theta]

    # check for inf/nan errors -> these sources have poor fits.
    if not all([ a is not None and np.isfinite(a) for a in pix_errs]):
        source.flags |= flags.FITERR
        source.err_peak_flux = source.err_a = source.err_b = source.err_pa = -1
        source.err_ra = source.err_dec = source.err_int_flux = -1
        return source

    # position errors
    if model[prefix + 'xo'].vary and model[prefix + 'yo'].vary:
        ref = wcshelper.pix2sky([xo,yo])
        offset = wcshelper.pix2sky([xo+err_xo,yo+err_yo])
        source.err_ra = gcd(ref[0], ref[1], offset[0], ref[1])
        source.err_dec = gcd(ref[0], ref[1], ref[0], offset[1])
    else:
        source.err_ra = source.err_dec = -1

    if model[prefix + 'sx'].vary and model[prefix + 'sy'].vary:
        # major axis error
        ref = wcshelper.pix2sky([xo+sx*np.cos(np.radians(theta)),yo+sy*np.sin(np.radians(theta))])
        offset = wcshelper.pix2sky([xo+(sx+err_sx)*np.cos(np.radians(theta)),yo+sy*np.sin(np.radians(theta))])
        source.err_a = gcd(ref[0],ref[1],offset[0],offset[1]) * 3600

        # minor axis error
        ref = wcshelper.pix2sky([xo+sx*np.cos(np.radians(theta+90)),yo+sy*np.sin(np.radians(theta+90))])
        offset = wcshelper.pix2sky([xo+sx*np.cos(np.radians(theta+90)),yo+(sy+err_sy)*np.sin(np.radians(theta+90))])
        source.err_b = gcd(ref[0], ref[1], offset[0], offset[1]) * 3600
    else:
        source.err_a = source.err_b = -1


    if model[prefix+'theta'].vary:
        # pa error
        ref = wcshelper.pix2sky([xo,yo])
        off1 = wcshelper.pix2sky([xo+sx*np.cos(np.radians(theta)),yo+sy*np.sin(np.radians(theta))])
        off2 = wcshelper.pix2sky([xo+sx*np.cos(np.radians(theta+err_theta)),yo+sy*np.sin(np.radians(theta+err_theta))])
        source.err_pa = abs(bear(ref[0], ref[1], off1[0], off1[1]) - bear(ref[0], ref[1], off2[0], off2[1]))
    else:
        source.err_pa = -1

    sqerr = 0
    sqerr += (source.err_peak_flux/source.peak_flux)**2 if source.err_peak_flux >0 else 0
    sqerr += (source.err_a/source.a)**2 if source.err_a > 0 else 0
    sqerr += (source.err_b/source.b)**2 if source.err_b > 0 else 0
    source.err_int_flux = source.int_flux*np.sqrt(sqerr)

    # logging.info("src ({0},{1})".format(source.island,source.source))
    # logging.info(" pixel errs {0}".format([err_xo, err_yo, err_sx, err_sy, err_theta]))
    # logging.info(" sky   errs {0}".format([source.err_ra, source.err_dec, source.err_a, source.err_b, source.err_pa]))
    return source
Beispiel #9
0
def errors(source, model, wcshelper):
    """
    Convert pixel based errors into sky coord errors
    :param source: Source object
    :param wcshelper: WCSHelper object
    :return:
    """

    # if the source wasn't fit then all errors are -1
    if source.flags & (flags.NOTFIT | flags.FITERR):
        source.err_peak_flux = source.err_a = source.err_b = source.err_pa = -1
        source.err_ra = source.err_dec = source.err_int_flux = -1
        return source
    # copy the errors from the model
    prefix = "c{0}_".format(source.source)
    err_amp = model[prefix + 'amp'].stderr
    xo, yo = model[prefix + 'xo'].value, model[prefix + 'yo'].value
    err_xo = model[prefix + 'xo'].stderr
    err_yo = model[prefix + 'yo'].stderr

    sx, sy = model[prefix + 'sx'].value, model[prefix + 'sy'].value
    err_sx = model[prefix + 'sx'].stderr
    err_sy = model[prefix + 'sy'].stderr

    theta = model[prefix + 'theta'].value
    err_theta = model[prefix + 'theta'].stderr

    source.err_peak_flux = err_amp
    pix_errs = [err_xo, err_yo, err_sx, err_sy, err_theta]

    # check for inf/nan errors -> these sources have poor fits.
    if not all([a is not None and np.isfinite(a) for a in pix_errs]):
        source.flags |= flags.FITERR
        source.err_peak_flux = source.err_a = source.err_b = source.err_pa = -1
        source.err_ra = source.err_dec = source.err_int_flux = -1
        return source

    # position errors
    if model[prefix + 'xo'].vary and model[prefix + 'yo'].vary:
        ref = wcshelper.pix2sky([xo, yo])
        offset = wcshelper.pix2sky([xo + err_xo, yo + err_yo])
        source.err_ra = gcd(ref[0], ref[1], offset[0], ref[1])
        source.err_dec = gcd(ref[0], ref[1], ref[0], offset[1])
    else:
        source.err_ra = source.err_dec = -1

    if model[prefix + 'sx'].vary and model[prefix + 'sy'].vary:
        # major axis error
        ref = wcshelper.pix2sky([
            xo + sx * np.cos(np.radians(theta)),
            yo + sy * np.sin(np.radians(theta))
        ])
        offset = wcshelper.pix2sky([
            xo + (sx + err_sx) * np.cos(np.radians(theta)),
            yo + sy * np.sin(np.radians(theta))
        ])
        source.err_a = gcd(ref[0], ref[1], offset[0], offset[1]) * 3600

        # minor axis error
        ref = wcshelper.pix2sky([
            xo + sx * np.cos(np.radians(theta + 90)),
            yo + sy * np.sin(np.radians(theta + 90))
        ])
        offset = wcshelper.pix2sky([
            xo + sx * np.cos(np.radians(theta + 90)),
            yo + (sy + err_sy) * np.sin(np.radians(theta + 90))
        ])
        source.err_b = gcd(ref[0], ref[1], offset[0], offset[1]) * 3600
    else:
        source.err_a = source.err_b = -1

    if model[prefix + 'theta'].vary:
        # pa error
        ref = wcshelper.pix2sky([xo, yo])
        off1 = wcshelper.pix2sky([
            xo + sx * np.cos(np.radians(theta)),
            yo + sy * np.sin(np.radians(theta))
        ])
        off2 = wcshelper.pix2sky([
            xo + sx * np.cos(np.radians(theta + err_theta)),
            yo + sy * np.sin(np.radians(theta + err_theta))
        ])
        source.err_pa = abs(
            bear(ref[0], ref[1], off1[0], off1[1]) -
            bear(ref[0], ref[1], off2[0], off2[1]))
    else:
        source.err_pa = -1

    sqerr = 0
    sqerr += (source.err_peak_flux /
              source.peak_flux)**2 if source.err_peak_flux > 0 else 0
    sqerr += (source.err_a / source.a)**2 if source.err_a > 0 else 0
    sqerr += (source.err_b / source.b)**2 if source.err_b > 0 else 0
    source.err_int_flux = source.int_flux * np.sqrt(sqerr)

    # logging.info("src ({0},{1})".format(source.island,source.source))
    # logging.info(" pixel errs {0}".format([err_xo, err_yo, err_sx, err_sy, err_theta]))
    # logging.info(" sky   errs {0}".format([source.err_ra, source.err_dec, source.err_a, source.err_b, source.err_pa]))
    return source