Beispiel #1
0
 def diag_size(self):
     """return the largest diagonal size"""
     p1, p2, p3, p4 = self.calc_footprint()
     return np.max([
         angular_separation(*np.concatenate([p1, p3])),
         angular_separation(*np.concatenate([p2, p4]))
     ])
Beispiel #2
0
 def edge_size(self):
     """return the p1,p2 and p2,p3 size (The order is counter-clockwise starting with
     the bottom left corner. p1,p2,p3,p4)"""
     p1, p2, p3, p4 = self.calc_footprint()
     return angular_separation(
         *np.concatenate([p1, p2])), angular_separation(
             *np.concatenate([p2, p3]))
Beispiel #3
0
    def solid_angle(self):
        """Solid angle array (`~astropy.units.Quantity` in ``sr``).

        The array has the same dimension as the WcsGeom object.

        To return solid angles for the spatial dimensions only use::

            WcsGeom.to_image().solid_angle()
        """
        coord = self.get_coord(mode="edges")
        lon = coord.lon * np.pi / 180.0
        lat = coord.lat * np.pi / 180.0

        # Compute solid angle across centres of the pixels, approximating it
        # as a rectangle
        # First index is "y", second index is "x"
        # TODO: Calculate actual solid angle between two great circles? Here are two references
        # suggesting more precise methods:
        # https://mail.python.org/pipermail/astropy/2013-December/002632.html
        # https://cta-redmine.irap.omp.eu/issues/1017
        lon_centres = (lon[..., :-1, :-1] + lon[..., 1:, 1:]) / 2
        lat_centres = (lat[..., :-1, :-1] + lat[..., 1:, 1:]) / 2

        ymid_xlo = lon[..., :-1, :-1], lat_centres
        ymid_xhi = lon[..., :-1, 1:], lat_centres
        ylo_xmid = lon_centres, lat[..., :-1, 1:]
        yhi_xmid = lon_centres, lat[..., 1:, :-1]

        dx = angular_separation(*(ymid_xlo + ymid_xhi))
        dy = angular_separation(*(ylo_xmid + yhi_xmid))

        return u.Quantity(dx * dy, "sr", copy=False)
Beispiel #4
0
def read_and_update_dl2(filepath, tel_id=1, filters=['intensity > 0']):
    """
    read DL2 data from lstchain file and update it to be compliant with irf Maker
    """
    dl2_params_lstcam_key = 'dl2/event/telescope/parameters/LST_LSTCam'  # lstchain DL2 files
    data = pd.read_hdf(filepath, key=dl2_params_lstcam_key)
    data = deepcopy(data.query(f'tel_id == {tel_id}'))
    for filter in filters:
        data = deepcopy(data.query(filter))

    # angles are in degrees in protopipe
    data['xi'] = pd.Series(angular_separation(
        data.reco_az.values * u.rad,
        data.reco_alt.values * u.rad,
        data.mc_az.values * u.rad,
        data.mc_alt.values * u.rad,
    ).to(u.deg).value,
                           index=data.index)

    data['offset'] = pd.Series(angular_separation(
        data.reco_az.values * u.rad,
        data.reco_alt.values * u.rad,
        data.mc_az_tel.values * u.rad,
        data.mc_alt_tel.values * u.rad,
    ).to(u.deg).value,
                               index=data.index)

    for key in [
            'mc_alt', 'mc_az', 'reco_alt', 'reco_az', 'mc_alt_tel', 'mc_az_tel'
    ]:
        data[key] = np.rad2deg(data[key])

    return data
Beispiel #5
0
    def solid_angle(self):
        """Solid angle array (`~astropy.units.Quantity` in ``sr``).

        The array has the same dimension as the WcsGeom object.

        To return solid angles for the spatial dimensions only use::

            WcsGeom.to_image().solid_angle()
        """
        coord = self.get_coord(mode="edges")
        lon = coord.lon * np.pi / 180.0
        lat = coord.lat * np.pi / 180.0

        # Compute solid angle across centres of the pixels, approximating it
        # as a rectangle
        # First index is "y", second index is "x"
        # TODO: Calculate actual solid angle between two great circles? Here are two references
        # suggesting more precise methods:
        # https://mail.python.org/pipermail/astropy/2013-December/002632.html
        # https://cta-redmine.irap.omp.eu/issues/1017
        lon_centres = (lon[..., :-1, :-1] + lon[..., 1:, 1:]) / 2
        lat_centres = (lat[..., :-1, :-1] + lat[..., 1:, 1:]) / 2

        ymid_xlo = lon[..., :-1, :-1], lat_centres
        ymid_xhi = lon[..., :-1, 1:], lat_centres
        ylo_xmid = lon_centres, lat[..., :-1, 1:]
        yhi_xmid = lon_centres, lat[..., 1:, :-1]

        dx = angular_separation(*(ymid_xlo + ymid_xhi))
        dy = angular_separation(*(ylo_xmid + yhi_xmid))

        return u.Quantity(dx * dy, "sr", copy=False)
Beispiel #6
0
    def solid_angle(self):
        """Solid angle array (`~astropy.units.Quantity` in ``sr``).

        The array has the same dimension as the WcsGeom object.
        To return solid angles for the spatial dimensions only use: WcsGeom.to_image().solid_angle()
        """
        # TODO: Improve by exposing a mode 'edge' for get_coord
        # Note that edge is applied only to spatial coordinates in the following call
        # Note also that pix_to_coord is already called in _get_pix_coords.
        # This should be made more efficient.
        pix = self._get_pix_coords(mode='edge')
        coord = self.pix_to_coord(pix)
        lon = coord[0] * np.pi / 180.
        lat = coord[1] * np.pi / 180.

        # Compute solid angle using the approximation that it's
        # the product between angular separation of pixel corners.
        # First index is "y", second index is "x"
        ylo_xlo = lon[..., :-1, :-1], lat[..., :-1, :-1]
        ylo_xhi = lon[..., :-1, 1:], lat[..., :-1, 1:]
        yhi_xlo = lon[..., 1:, :-1], lat[..., 1:, :-1]

        dx = angular_separation(*(ylo_xlo + ylo_xhi))
        dy = angular_separation(*(ylo_xlo + yhi_xlo))

        return u.Quantity(dx * dy, 'sr')
Beispiel #7
0
    def coarse_quad_search(self, obsjd, quads, objects, vlim):
        """Nearest-neighbor search.

        Parameters
        ----------
        obsjd : float
          Julian date.
        quads : list of lists
          Each item is a list of quadrant parameters:
            obsjd, pid, ra_c, dec_c, ra1, ra2, ra3, ra4, dec1, dec2, dec3, dec4
          where 1..4 are coordinates of the corners.
        objects : list of string
          Objects.
        vlim : float
          Limiting magnitude to consider.

        Returns
        -------
        objects : list
          Found objects.
        quads : list
          Nearest 4 quads for each object.

        """

        import numpy as np
        from astropy.coordinates.angle_utilities import angular_separation
        from .exceptions import EphemerisError

        (ra_c, dec_c, ra1, ra2, ra3, ra4,
         dec1, dec2, dec3, dec4) = tuple(zip(*quads))[2:]

        found = []
        for obj in objects:
            try:
                ra, dec, vmag = self._get_ephemeris(obj, obsjd)
            except EphemerisError as e:
                self.logger.debug(str(e))
                continue

            # vmag greater than vlim?  skip.
            if vmag > vlim:
                continue

            # farther than 12 deg from any corner?  forget it
            if angular_separation(ra, dec, ra_c[0], dec_c[0]) > 0.21:
                continue

            # Farther than 1.5 deg from any quad?  skip.
            d = angular_separation(ra, dec, ra_c, dec_c)
            if min(d) > 0.026:
                continue

            found.append((obj, [quads[i] for i in np.argsort(d)[:4]]))

        return found
Beispiel #8
0
    def evaluate(self, lon, lat, lon_0, lat_0, semi_major, e, theta, edge):
        """Evaluate the model (static function)."""
        # find the foci of the ellipse
        c = semi_major * e
        lon_1, lat_1 = self._offset_by(lon_0, lat_0, 90 * u.deg - theta, c)
        lon_2, lat_2 = self._offset_by(lon_0, lat_0, 270 * u.deg - theta, c)

        sep_1 = angular_separation(lon, lat, lon_1, lat_1)
        sep_2 = angular_separation(lon, lat, lon_2, lat_2)

        in_ellipse = smooth_edge(sep_1 + sep_2 - 2 * semi_major, edge)

        norm = SkyEllipse.compute_norm(semi_major, e)
        return u.Quantity(norm * in_ellipse, "sr-1", copy=False)
Beispiel #9
0
    def evaluate(self, lon, lat, lon_0, lat_0, semi_major, e, theta, edge):
        """Evaluate the model (static function)."""
        # find the foci of the ellipse
        c = semi_major * e
        lon_1, lat_1 = self._offset_by(lon_0, lat_0, 90 * u.deg - theta, c)
        lon_2, lat_2 = self._offset_by(lon_0, lat_0, 270 * u.deg - theta, c)

        sep_1 = angular_separation(lon, lat, lon_1, lat_1)
        sep_2 = angular_separation(lon, lat, lon_2, lat_2)

        in_ellipse = smooth_edge(sep_1 + sep_2 - 2 * semi_major, 2 * edge)

        norm = SkyEllipse.compute_norm(semi_major, e)
        return u.Quantity(norm * in_ellipse, "sr-1", copy=False)
Beispiel #10
0
    def __init__(self, ra, dec, trigger_time, ft2file, degree=2):

        # Open the FT2 file and read the pointing information
        with pyfits.open(ft2file) as f:

            # Remember: in the FT2 all quantities (except the livetime) refer to the START time
            time = f['SC_DATA'].data['START']

            # Read the position of the Z-axis (the boresight) and convert it to radians
            ra_scz_rad = np.deg2rad(f['SC_DATA'].data['RA_SCZ'])
            dec_scz_rad = np.deg2rad(f['SC_DATA'].data['DEC_SCZ'])

        # Prepare the interpolator
        ang_dist_rad = angular_separation(ra_scz_rad, dec_scz_rad, np.deg2rad(ra), np.deg2rad(dec))

        self._theta_interpolator_radians = scipy.interpolate.InterpolatedUnivariateSpline(time - trigger_time,
                                                                                          ang_dist_rad,
                                                                                          w=np.ones_like(ang_dist_rad),
                                                                                          k=2,
                                                                                          ext=2,
                                                                                          check_finite=True)

        # Store the trigegr time as reference time
        self._reference_time = float(trigger_time)

        self._degree = int(degree)

        self._scales = np.ones(self._degree+1)

        self.clip_at_zero = False
Beispiel #11
0
def calculate_source_fov_offset(events, prefix="true"):
    """Calculate angular separation between true and pointing positions.

    Parameters
    ----------
    events : astropy.QTable
        Astropy Table object containing the reconstructed events information.

    prefix: str
        Column prefix for az / alt, can be used to calculate reco or true
        source fov offset.

    Returns
    -------
    theta: astropy.units.Quantity
        Angular separation between the true and pointing positions
        in the sky.
    """
    theta = angular_separation(
        events[f"{prefix}_az"],
        events[f"{prefix}_alt"],
        events["pointing_az"],
        events["pointing_alt"],
    )

    return theta.to(u.deg)
Beispiel #12
0
    def compute_constraint(self, times, observer, targets):
        moon = get_moon(times, observer.location, observer.pressure)
        targets = [target.coord if hasattr(target, 'coord') else target
                   for target in targets]

        moon_separation = Angle([angular_separation(moon.spherical.lon,
                                                    moon.spherical.lat,
                                                    target.spherical.lon,
                                                    target.spherical.lat)
                                 for target in targets])
        # The line below should have worked, but needs a workaround.
        # TODO: once bug has been fixed, replace workaround with simpler version.
        # Relevant PR: https://github.com/astropy/astropy/issues/4033
#        moon_separation = Angle([moon.separation(target) for target in targets])
        if self.min is None and self.max is not None:
            mask = self.max > moon_separation
        elif self.max is None and self.min is not None:
            mask = self.min < moon_separation
        elif self.min is not None and self.max is not None:
            mask = ((self.min < moon_separation) &
                    (moon_separation < self.max))
        else:
            raise ValueError("No max and/or min specified in "
                             "MoonSeparationConstraint.")
        return mask
Beispiel #13
0
def moon_phase_angle(time, location):
    """
    Calculate lunar orbital phase [radians].

    Parameters
    ----------
    time : `~astropy.time.Time`
        Time of observation

    location : `~astropy.coordinates.EarthLocation`
        Location of observer

    Returns
    -------
    i : float
        Phase angle of the moon [radians]
    """
    # TODO: cache these sun/moon SkyCoord objects
    sun = get_sun(time).transform_to(AltAz(location=location, obstime=time))
    moon = get_moon(time, location)
    # The line below should have worked, but needs a workaround.
    # TODO: once bug has been fixed, replace workaround with simpler version.
    # elongation = sun.separation(moon)
    elongation = Angle(angular_separation(moon.spherical.lon,
                                   moon.spherical.lat,
                                   sun.spherical.lon,
                                   sun.spherical.lat), u.deg)
    return np.arctan2(sun.distance*np.sin(elongation),
                      moon.distance - sun.distance*np.cos(elongation))
Beispiel #14
0
def triangle_test(p, v):
    """Test if point p lies within the triangle with vertices v.

    All points in units of raidans.

    Edges and vertices are included.

    Assumes points are located on the unit sphere.

    http://mathworld.wolfram.com/TriangleInterior.html

    """

    import numpy as np
    from astropy.coordinates.angle_utilities import (
        angular_separation, position_angle)

    # project coordinate system about p to avoid polar and boundary issues
    # Zenithal projection
    th = angular_separation(p[0], p[1], v[:, 0], v[:, 1])
    phi = position_angle(p[0], p[1], v[:, 0], v[:, 1])
    x = np.c_[th * np.sin(phi), -th * np.cos(phi)]

    a = x[1] - x[0]
    b = x[2] - x[0]
    #s = (np.cross(p, b) - np.cross(v[0], b)) / np.cross(a, b)
    #t = -(np.cross(p, a) - np.cross(v[0], a)) / np.cross(a, b)
    s = -np.cross(x[0], b) / np.cross(a, b)
    t = np.cross(x[0], a) / np.cross(a, b)
    return (s >= 0) * (t >= 0) * (s + t <= 1)
Beispiel #15
0
    def compute_constraint(self, times, observer, targets):
        moon = get_moon(times, observer.location, observer.pressure)
        targets = [
            target.coord if hasattr(target, 'coord') else target
            for target in targets
        ]

        moon_separation = Angle([
            angular_separation(moon.spherical.lon, moon.spherical.lat,
                               target.spherical.lon, target.spherical.lat)
            for target in targets
        ])
        # The line below should have worked, but needs a workaround.
        # TODO: once bug has been fixed, replace workaround with simpler version.
        # Relevant PR: https://github.com/astropy/astropy/issues/4033
        #        moon_separation = Angle([moon.separation(target) for target in targets])
        if self.min is None and self.max is not None:
            mask = self.max >= moon_separation
        elif self.max is None and self.min is not None:
            mask = self.min <= moon_separation
        elif self.min is not None and self.max is not None:
            mask = ((self.min <= moon_separation) &
                    (moon_separation <= self.max))
        else:
            raise ValueError("No max and/or min specified in "
                             "MoonSeparationConstraint.")
        return mask
Beispiel #16
0
def moon_phase_angle(time, location):
    """
    Calculate lunar orbital phase [radians].

    Parameters
    ----------
    time : `~astropy.time.Time`
        Time of observation

    location : `~astropy.coordinates.EarthLocation`
        Location of observer

    Returns
    -------
    i : float
        Phase angle of the moon [radians]
    """
    # TODO: cache these sun/moon SkyCoord objects
    sun = get_sun(time).transform_to(AltAz(location=location, obstime=time))
    moon = get_moon(time, location)
    # The line below should have worked, but needs a workaround.
    # TODO: once bug has been fixed, replace workaround with simpler version.
    # elongation = sun.separation(moon)
    elongation = Angle(
        angular_separation(moon.spherical.lon, moon.spherical.lat,
                           sun.spherical.lon, sun.spherical.lat), u.deg)
    return np.arctan2(sun.distance * np.sin(elongation),
                      moon.distance - sun.distance * np.cos(elongation))
Beispiel #17
0
def calculate_theta(events, assumed_source_az, assumed_source_alt):
    """Calculate sky separation between assumed and reconstructed positions.

    Parameters
    ----------
    events : astropy.QTable
        Astropy Table object containing the reconstructed events information.
    assumed_source_az: astropy.units.Quantity
        Assumed Azimuth angle of the source.
    assumed_source_alt: astropy.units.Quantity
        Assumed Altitude angle of the source.

    Returns
    -------
    theta: astropy.units.Quantity
        Angular separation between the assumed and reconstructed positions
        in the sky.
    """
    theta = angular_separation(
        assumed_source_az,
        assumed_source_alt,
        events["reco_az"],
        events["reco_alt"],
    )

    return theta.to(u.deg)
def f(params, row, col, alt, az):
    print(params)
    zenith_row, zenith_col, rotation = params

    magic_2018.zenith_row = zenith_row + magic_2018.sensor.resolution_row / 2
    magic_2018.zenith_col = zenith_col + magic_2018.sensor.resolution_col / 2
    magic_2018.rotation = rotation * u.deg
    magic_2018.lens.mapping = 'spline'

    r, phi = magic_2018.pixel2polar(row, col)
    r *= magic_2018.sensor.pixel_width.to(u.mm).value

    x = np.append(0, r)
    y = np.append(0, 90 - alt)

    idx = np.argsort(x)

    tck = splrep(x[idx],
                 y[idx],
                 t=np.linspace(np.percentile(x, 1), np.percentile(x, 99), 10))
    magic_2018.lens.tck_inv = tck

    coords = magic_2018.pixel2horizontal(row, col)

    val = angular_separation(alt * u.deg, az * u.deg, coords.alt,
                             coords.az).value.mean()
    return val
Beispiel #19
0
 def evaluate(lon, lat, lon_0, lat_0, sigma):
     """Evaluate the model (static function)."""
     sep = angular_separation(lon, lat, lon_0, lat_0)
     a = 1.0 - np.cos(sigma)
     norm = 1 / (4 * np.pi * a * (1.0 - np.exp(-1.0 / a)))
     exponent = -0.5 * ((1 - np.cos(sep)) / a)
     return u.Quantity(norm.value * np.exp(exponent).value, "sr-1", copy=False)
Beispiel #20
0
    def search_for_maximum(self, ra_center, dec_center, half_side_deg, n_side, proj_name='AIT', verbose=False):
        """

        :param ra_center: R.A. of the center of the map
        :param dec_center: Dec of the center of the map
        :param half_size_deg: half size of the side of the TS map ("radius", even though it is a square)
        :param n_side: number of points on one side. So n_side = 5 means that a 5x5 map will be computed
        :param stepsize: size of the step, i.e., distance between two adiancent points in the RA or Dec direction
        :param proj_name: name for the projection (default: AIT). All projections supported by astropy.wcs can be used
        :return: (max_ts_position, max_ts): returns a tuple of (RA, Dec) and the maximum TS found
        """

        # Figure out step size
        stepsize = half_side_deg / (n_side / 2.0)

        # Create WCS object which will allow us to make the grid

        wcs = pywcs.WCS(naxis=2)
        wcs.wcs.crpix = [n_side / 2. + 0.5, n_side / 2. + 0.5]
        wcs.wcs.cdelt = [-stepsize, stepsize]
        wcs.wcs.crval = [float(ra_center), float(dec_center)]
        wcs.wcs.ctype = ["RA---%s" % proj_name, "DEC--%s" % proj_name]

        # Compute all TSs

        # These two will hold maximum and position of the maximum
        # Init them with worse case scenario
        max_ts = 0.0
        max_ts_position = (ra_center, dec_center)
        ang_sep = []

        for i in range(n_side):

            for j in range(n_side):

                this_ra, this_dec = wcs.wcs_pix2world(i, j, 0)

                this_TS = self._calc_one_TS(float(this_ra), float(this_dec))

                if this_TS >= max_ts:

                    # New maximum
                    max_ts = this_TS
                    max_ts_position = (this_ra, this_dec)

                if verbose:

                    ang_sep.append(np.rad2deg(angular_separation(*np.deg2rad([ra_center, dec_center,
                                                                              this_ra, this_dec]))))

                    print("(%.3f, %.3f) -> %.2f (%.3f deg away from center)" % (this_ra, this_dec,
                                                                                this_TS, ang_sep[-1]))

        if verbose:
            print("Total number of points: %i" % len(ang_sep))
            print("Minimum ang. dist: %s deg" % min(ang_sep))
            print("Maximum ang. dist: %s deg" % max(ang_sep))

        # Find maximum and its position
        return max_ts_position, max_ts
Beispiel #21
0
def const_score(tb, ob, times, site):
    """
    calculates a score for an OB thar represents how well it would fit here,
    infinity if constraints make it unobservable
    Remember: Lower numbers are better
    """
    moon = astroplan.get_moon(times, site.location, site.pressure)

    altaz = site.altaz(times, ob.target)
    if np.any(altaz.alt < ob.constraints[1].min) or np.any(altaz.alt > ob.constraints[1].max):
        return float('inf')	# altitude constraint
    if np.any(site.moon_illumination(times) > ob.constraints[2].max):
        return float('inf')	# moon illumination constraint
    moon_sep = astropy.coordinates.Angle([angular_separation(moon.spherical.lon,
                                                             moon.spherical.lat,
                                                             ob.target.coord.spherical.lon,
                                                             ob.target.coord.spherical.lat)])
    if np.any(moon_sep < ob.constraints[0].min):
        return float('inf')	# moon separation constraint
    score = 0.
    score += ob.priority*weights.w_priority	# the marked priority
    score += ob.program.rank*weights.w_rank	# the rank of the program
    if tb is not None:
	# the time to slew
        score += tb.components.get('slew_time', 0*u.second).value*weights.w_slew	
	# the time to change filter
        score += tb.components.get('filter_change',
                                   0*u.second).value*weights.w_filterchange
        
    return score
Beispiel #22
0
def process_mc(simtelfile, dl2_file, mc_type):
    """
    Process the MC simulated and reconstructed to extract the relevant
    parameters to compute the sensitivity

    Paramenters
    ---------
    simtel: simtelarray file
    dl2_file: `pandas.DataFrame` dl2 parameters
    mc_type: 'string' type of particle

    Returns
    ---------
    gammaness: `numpy.ndarray`
    angdist2:  `numpy.ndarray` angular distance squared
    e_reco:    `numpy.ndarray` reconstructed energies
    n_reco:    `int` number of reconstructed events
    mc_par:    `dict` with simulated parameters

    """
    source = SimTelFile(simtelfile)
    sim_par = read_sim_par(source)
    events = pd.read_hdf(dl2_file)

    e_reco = 10**events.mc_energy.to_numpy() * u.GeV
    gammaness = events.gammaness

    #Get source position in radians

    focal_length = source.telescope_descriptions[1]['camera_settings']['focal_length'] * u.m


    # If the particle is a gamma ray, it returns the squared angular distance
    # from the reconstructed gamma-ray position and the simulated incoming position
    if mc_type=='gamma':
        events = events[events.mc_type==0]
        alt2 = events.mc_alt
        az2 = np.arctan(np.tan(events.mc_az))

    # If the particle is not a gamma-ray (diffuse protons/electrons), it returns
    # the squared angular distance of the reconstructed position w.r.t. the
    # center of the camera
    else:
        events = events[events.mc_type!=0]
        alt2 = events.mc_alt_tel
        az2 = np.arctan(np.tan(events.mc_az_tel))

    src_pos_reco = reco_source_position_sky(events.x.values * u.m,
                                            events.y.values * u.m,
                                            events.disp_dx_rec.values * u.m,
                                            events.disp_dy_rec.values * u.m,
                                            focal_length,
                                            events.mc_alt_tel.values * u.rad,
                                            events.mc_az_tel.values * u.rad)

    alt1 = src_pos_reco.alt.rad
    az1 = np.arctan(np.tan(src_pos_reco.az.rad))

    angdist2 = (angular_separation(az1, alt1, az2, alt2).to_numpy() * u.rad)**2
    return gammaness, angdist2.to(u.deg**2), e_reco, sim_par
Beispiel #23
0
def pair_correlation(lon, lat, theta_bins):
    """Compute pair correlation function for points on the sphere.

    Parameters
    ----------
    lon, lat : array_like
        Coordinate arrays
    theta_bins : array_like
        Array defining the ``theta`` binning.
        ``theta`` is the angular offset between positions.
    unit : {'deg', 'rad'}
        Units of input and output coordinates

    Returns
    -------
    counts : array
        Array of point separations per ``theta`` bin.
    """
    # TODO: Implement speedups:
    # - use radians
    # - avoid processing each pair twice (distance a to b and b to a)
    counts = np.zeros(shape=len(theta_bins) - 1, dtype=int)
    # If there are many points this should have acceptable performance
    # because the inner loop is in np.histogram, not in Python
    for ii in range(len(lon)):
        theta = angular_separation(lon[ii], lat[ii], lon, lat)
        hist = np.histogram(theta, theta_bins)[0]
        counts += hist

    return counts
Beispiel #24
0
def minimum_separation(lon1, lat1, lon2, lat2):
    """Compute minimum distance of each (lon1, lat1) to any (lon2, lat2).

    Parameters
    ----------
    lon1, lat1 : array_like
        Primary coordinates of interest
    lon2, lat2 : array_like
        Counterpart coordinate array
    unit : {'deg', 'rad'}
        Units of input and output coordinates

    Returns
    -------
    theta_min : array
        Minimum distance
    """
    lon1 = np.asanyarray(lon1)
    lat1 = np.asanyarray(lat1)

    theta_min = np.empty_like(lon1, dtype=np.float64)

    for i1 in range(lon1.size):
        thetas = angular_separation(lon1[i1], lat1[i1], lon2, lat2)
        theta_min[i1] = thetas.min()

    return theta_min
Beispiel #25
0
def anglesep(lon0: float,
             lat0: float,
             lon1: float,
             lat1: float,
             deg: bool = True) -> float:
    """
    inputs: DEGREES

    For reference, this is from astropy astropy/coordinates/angle_utilities.py
    Angular separation between two points on a sphere.
    """
    if angular_separation is None:
        raise ImportError('angledist requires AstroPy. Try angledis_meeus')

    if deg:
        lon0 = radians(lon0)
        lat0 = radians(lat0)
        lon1 = radians(lon1)
        lat1 = radians(lat1)

    sep_rad = angular_separation(lon0, lat0, lon1, lat1)

    if deg:
        return degrees(sep_rad)
    else:
        return sep_rad
Beispiel #26
0
    def evaluate(lon, lat, lon_0, lat_0, r_0):
        """Evaluate the model (static function)."""
        sep = angular_separation(lon, lat, lon_0, lat_0)

        # Surface area of a spherical cap, see https://en.wikipedia.org/wiki/Spherical_cap
        norm = 1.0 / (2 * np.pi * (1 - np.cos(r_0)))
        return u.Quantity(norm.value * (sep <= r_0), "sr-1", copy=False)
Beispiel #27
0
def process_mc(dl2_file, mc_type):
    """
    Process the MC simulated and reconstructed to extract the relevant
    parameters to compute the sensitivity

    Parameters
    ----------
    dl2_file:  dl2 file with mc parameters
    events: `pandas DataFrame' dl2 events
    mc_type: 'string' type of particle

    Returns
    -------
    gammaness: `numpy.ndarray`
    angdist2:  `numpy.ndarray` angular distance squared
    e_reco:    `numpy.ndarray` reconstructed energies
    n_reco:    `int` number of reconstructed events
    mc_par:    `dict` with simulated parameters

    """
    sim_par = read_sim_par(dl2_file)

    events = pd.read_hdf(dl2_file, key=dl2_params_lstcam_key)

    # Filters:
    # TO DO: These cuts must be given in a configuration file
    # By now: only cut in leakage and intensity
    # we use all telescopes (number of events needs to be multiplied
    # by the number of LSTs in the simulation)

    filter_good_events = ((events.leakage_intensity_width_2 < 0.2)
                          & (events.intensity > 100))
    events = events[filter_good_events]

    e_reco = events.reco_energy.to_numpy() * u.TeV
    e_true = events.mc_energy.to_numpy() * u.TeV

    gammaness = events.gammaness

    # If the particle is a gamma ray, it returns the squared angular distance
    # from the reconstructed gamma-ray position and the simulated incoming position
    if mc_type == 'gamma':
        alt2 = events.mc_alt
        az2 = events.mc_az

    # If the particle is not a gamma-ray (diffuse protons/electrons), it returns
    # the squared angular distance of the reconstructed position w.r.t. the
    # center of the camera
    else:
        alt2 = events.mc_alt_tel
        az2 = events.mc_az_tel

    alt1 = events.reco_alt
    az1 = events.reco_az

    angdist2 = (angular_separation(az1, alt1, az2, alt2).to_numpy() * u.rad)**2
    events['theta2'] = angdist2.to_value(u.deg**2)

    return gammaness, angdist2.to(u.deg**2), e_reco, e_true, sim_par, events
Beispiel #28
0
def angledist(lon1, lat1, lon2, lat2):
    """
    For reference, this is from astropy astropy/coordinates/angle_utilities.py
    Angular separation between two points on a sphere.
    """
    return degrees(
        angular_separation(radians(lon1), radians(lat1), radians(lon2),
                           radians(lat2)))
Beispiel #29
0
def angledist_astropy(lon1, lat1, lon2, lat2):
    """
    For reference, this is from astropy astropy/coordinates/angle_utilities.py
    Angular separation between two points on a sphere.
    """
    return degrees(angular_separation(radians(lon1),
                                      radians(lat1), radians(lon2),
                                      radians(lat2)))
Beispiel #30
0
def test_fk4_no_e_fk5():
    lines = get_pkg_data_contents('data/fk4_no_e_fk5.csv').split('\n')
    t = Table.read(lines, format='ascii', delimiter=',', guess=False)

    if N_ACCURACY_TESTS >= len(t):
        idxs = range(len(t))
    else:
        idxs = np.random.randint(len(t), size=N_ACCURACY_TESTS)

    diffarcsec1 = []
    diffarcsec2 = []
    for i in idxs:
        # Extract row
        r = t[int(i)]  # int here is to get around a py 3.x astropy.table bug

        # FK4NoETerms to FK5
        c1 = FK4NoETerms(ra=r['ra_in'] * u.deg,
                         dec=r['dec_in'] * u.deg,
                         obstime=Time(r['obstime']),
                         equinox=Time(r['equinox_fk4']))
        c2 = c1.transform_to(FK5(equinox=Time(r['equinox_fk5'])))

        # Find difference
        diff = angular_separation(c2.ra.radian, c2.dec.radian,
                                  np.radians(r['ra_fk5']),
                                  np.radians(r['dec_fk5']))

        diffarcsec1.append(np.degrees(diff) * 3600.)

        # FK5 to FK4NoETerms
        c1 = FK5(ra=r['ra_in'] * u.deg,
                 dec=r['dec_in'] * u.deg,
                 equinox=Time(r['equinox_fk5']))
        fk4neframe = FK4NoETerms(obstime=Time(r['obstime']),
                                 equinox=Time(r['equinox_fk4']))
        c2 = c1.transform_to(fk4neframe)

        # Find difference
        diff = angular_separation(c2.ra.radian, c2.dec.radian,
                                  np.radians(r['ra_fk4']),
                                  np.radians(r['dec_fk4']))

        diffarcsec2.append(np.degrees(diff) * 3600.)

    np.testing.assert_array_less(diffarcsec1, TOLERANCE)
    np.testing.assert_array_less(diffarcsec2, TOLERANCE)
Beispiel #31
0
 def evaluate(lon, lat, lon_0, lat_0, r_0, eta, e, phi):
     sep = angular_separation(lon, lat, lon_0, lat_0)
     if isinstance(eta, u.Quantity):
         eta = eta.value  # gamma function does not allow quantities
     minor_axis, r_eff = compute_sigma_eff(lon_0, lat_0, lon, lat, phi, r_0, e)
     z = sep / r_eff
     norm = 1 / (2 * np.pi * minor_axis * r_0 * eta * scipy.special.gamma(2 * eta))
     return (norm * np.exp(-(z ** (1 / eta)))).to("sr-1")
Beispiel #32
0
    def evaluate(lon, lat, lon_0, lat_0, r_0, edge):
        """Evaluate model."""
        sep = angular_separation(lon, lat, lon_0, lat_0)

        # Surface area of a spherical cap, see https://en.wikipedia.org/wiki/Spherical_cap
        norm = 1.0 / (2 * np.pi * (1 - np.cos(r_0)))

        in_disk = smooth_edge(sep - r_0, edge)
        return u.Quantity(norm.value * in_disk, "sr-1", copy=False)
Beispiel #33
0
def fov_offset(df):
    pointing_lat = (90 - df.aux_pointing_position_zd.values) * u.deg
    pointing_lon = df.aux_pointing_position_az.values * u.deg

    source_lat = (90 - df.source_position_zd.values) * u.deg
    source_lon = df.source_position_az.values * u.deg

    return angular_separation(pointing_lon, pointing_lat, source_lon,
                              source_lat)
Beispiel #34
0
def calculate_distance_to_true_source_position(df):
    source_az = Angle(df.mc_az.values * u.deg).wrap_at(180 * u.deg)
    source_alt = Angle(df.mc_alt.values * u.deg)

    az = Angle(df.az.values * u.deg).wrap_at(180 * u.deg)
    alt = Angle(df.alt.values * u.deg)

    distance = angular_separation(source_az, source_alt, az, alt).to(u.deg)
    return distance
Beispiel #35
0
    def evaluate(lon, lat, lon_0, lat_0, r_0, edge):
        """Evaluate the model (static function)."""
        sep = angular_separation(lon, lat, lon_0, lat_0)

        # Surface area of a spherical cap, see https://en.wikipedia.org/wiki/Spherical_cap
        norm = 1.0 / (2 * np.pi * (1 - np.cos(r_0)))

        in_disk = smooth_edge(sep - r_0, edge)
        return u.Quantity(norm.value * in_disk, "sr-1", copy=False)
Beispiel #36
0
def calculate_distance_to_point_source(df, source_alt, source_az):
    source_az = Angle(source_az).wrap_at(180 * u.deg)
    source_alt = Angle(source_alt)

    az = Angle(df.az.values * u.deg).wrap_at(180 * u.deg)
    alt = Angle(df.alt.values * u.deg)

    distance = angular_separation(source_az, source_alt, az, alt).to(u.deg)
    return distance
Beispiel #37
0
 def evaluate(lon, lat, lon_0, lat_0, sigma):
     """Evaluate the model (static function)."""
     sep = angular_separation(lon, lat, lon_0, lat_0)
     a = 1.0 - np.cos(sigma)
     norm = 1 / (4 * np.pi * a * (1.0 - np.exp(-1.0 / a)))
     exponent = -0.5 * ((1 - np.cos(sep)) / a)
     return u.Quantity(norm.value * np.exp(exponent).value,
                       "sr-1",
                       copy=False)
Beispiel #38
0
def test_fk4_no_e_fk5():
    lines = get_pkg_data_contents('fk4_no_e_fk5.csv').split('\n')
    t = Table.read(lines, format='ascii', delimiter=',', guess=False)

    if N_ACCURACY_TESTS >= len(t):
        idxs = range(len(t))
    else:
        idxs = np.random.randint(len(t), size=N_ACCURACY_TESTS)

    diffarcsec1 = []
    diffarcsec2 = []
    for i in idxs:
        # Extract row
        r = t[int(i)]  # int here is to get around a py 3.x astropy.table bug

        # FK4NoETerms to FK5
        c1 = FK4NoETerms(ra=r['ra_in']*u.deg, dec=r['dec_in']*u.deg,
                         obstime=Time(r['obstime'], scale='utc'),
                         equinox=Time(r['equinox_fk4'], scale='utc'))
        c2 = c1.transform_to(FK5(equinox=Time(r['equinox_fk5'], scale='utc')))

        # Find difference
        diff = angular_separation(c2.ra.radian, c2.dec.radian,
                                  np.radians(r['ra_fk5']),
                                  np.radians(r['dec_fk5']))

        diffarcsec1.append(np.degrees(diff) * 3600.)

        # FK5 to FK4NoETerms
        c1 = FK5(ra=r['ra_in']*u.deg, dec=r['dec_in']*u.deg,
                 equinox=Time(r['equinox_fk5'], scale='utc'))
        fk4neframe = FK4NoETerms(obstime=Time(r['obstime'], scale='utc'),
                                 equinox=Time(r['equinox_fk4'], scale='utc'))
        c2 = c1.transform_to(fk4neframe)

        # Find difference
        diff = angular_separation(c2.ra.radian, c2.dec.radian,
                                  np.radians(r['ra_fk4']),
                                  np.radians(r['dec_fk4']))

        diffarcsec2.append(np.degrees(diff) * 3600.)

    np.testing.assert_array_less(diffarcsec1, TOLERANCE)
    np.testing.assert_array_less(diffarcsec2, TOLERANCE)
Beispiel #39
0
    def evaluate(lon, lat, lon_0, lat_0, r_0):
        """Evaluate the model (static function)."""
        sep = angular_separation(lon, lat, lon_0, lat_0)
        sep = sep.to('rad').value
        r_0 = r_0.to('rad').value

        norm = 1. / (2 * np.pi * (1 - np.cos(r_0)))
        val = np.where(sep <= r_0, norm, 0)

        return val * u.Unit('sr-1')
Beispiel #40
0
    def solid_angle(self):
        """
        Solid angle image (2-dim `~astropy.units.Quantity` in `sr`).
        """
        coordinates = self.coordinates(mode='edges')
        lon = coordinates.data.lon.radian
        lat = coordinates.data.lat.radian

        # Compute solid angle using the approximation that it's
        # the product between angular separation of pixel corners.
        # First index is "y", second index is "x"
        ylo_xlo = lon[:-1, :-1], lat[:-1, :-1]
        ylo_xhi = lon[:-1, 1:], lat[:-1, 1:]
        yhi_xlo = lon[1:, :-1], lat[1:, :-1]

        dx = angular_separation(*(ylo_xlo + ylo_xhi))
        dy = angular_separation(*(ylo_xlo + yhi_xlo))
        omega = u.Quantity(dx * dy, 'sr')
        return omega
Beispiel #41
0
    def solid_angle(self):
        """
        Solid angle image (2-dim `~astropy.units.Quantity` in `sr`).
        """
        coordinates = self.coordinates(mode='edges')
        lon = coordinates.data.lon.radian
        lat = coordinates.data.lat.radian

        # Compute solid angle using the approximation that it's
        # the product between angular separation of pixel corners.
        # First index is "y", second index is "x"
        ylo_xlo = lon[:-1, :-1], lat[:-1, :-1]
        ylo_xhi = lon[:-1, 1:], lat[:-1, 1:]
        yhi_xlo = lon[1:, :-1], lat[1:, :-1]

        dx = angular_separation(*(ylo_xlo + ylo_xhi))
        dy = angular_separation(*(ylo_xlo + yhi_xlo))
        omega = u.Quantity(dx * dy, 'sr')
        return omega
Beispiel #42
0
    def _pix_cen(self):
        """
        Offset of every pixel from the origin, along each direction

        Returns
        -------
        tuple of spectral_offset, y_offset, x_offset, each 3D arrays
        describing the distance from the origin

        Notes
        -----
        These arrays are broadcast, and are not memory intensive

        Each array is in the units of the corresponding wcs.cunit, but
        this is implicit (e.g., they are not astropy Quantity arrays)
        """
        # Start off by extracting the world coordinates of the pixels
        _, lat, lon = self.world[0, :, :]
        spectral, _, _ = self.world[:, 0, 0]

        # Convert to radians
        lon = np.radians(lon)
        lat = np.radians(lat)

        # Find the dx and dy arrays
        from astropy.coordinates.angle_utilities import angular_separation
        dx = angular_separation(lon[:, :-1], lat[:, :-1],
                                lon[:, 1:], lat[:, :-1])
        dy = angular_separation(lon[:-1, :], lat[:-1, :],
                                lon[1:, :], lat[1:, :])

        # Find the cumulative offset - need to add a zero at the start
        x = np.zeros(self._data.shape[1:])
        y = np.zeros(self._data.shape[1:])
        x[:, 1:] = np.cumsum(np.degrees(dx), axis=1)
        y[1:, :] = np.cumsum(np.degrees(dy), axis=0)

        x = x.reshape(1, x.shape[0], x.shape[1])
        y = y.reshape(1, y.shape[0], y.shape[1])
        spectral = spectral.reshape(-1, 1, 1) - spectral.ravel()[0]
        x, y, spectral = np.broadcast_arrays(x, y, spectral)
        return spectral, y, x
Beispiel #43
0
def angular_separation_deg_to_arcsec(lon1, lat1, lon2, lat2):
    from astropy.coordinates.angle_utilities import angular_separation
    from astropy.coordinates import Angle
    lon1 = np.radians(lon1)
    lat1 = np.radians(lat1)
    lon2 = np.radians(lon2)
    lat2 = np.radians(lat2)

    separation = angular_separation(lon1, lat1, lon2, lat2)

    return Angle(separation, 'radian').to('arcsec').value
Beispiel #44
0
def test_galactic_fk4():
    lines = get_pkg_data_contents('data/galactic_fk4.csv').split('\n')
    t = Table.read(lines, format='ascii', delimiter=',', guess=False)

    if N_ACCURACY_TESTS >= len(t):
        idxs = range(len(t))
    else:
        idxs = np.random.randint(len(t), size=N_ACCURACY_TESTS)

    diffarcsec1 = []
    diffarcsec2 = []
    for i in idxs:
        # Extract row
        r = t[int(i)]  # int here is to get around a py 3.x astropy.table bug

        # Galactic to FK4
        c1 = Galactic(l=r['lon_in']*u.deg, b=r['lat_in']*u.deg)
        c2 = c1.transform_to(FK4(equinox=Time(r['equinox_fk4'], scale='utc')))

        # Find difference
        diff = angular_separation(c2.ra.radian, c2.dec.radian,
                                  np.radians(r['ra_fk4']),
                                  np.radians(r['dec_fk4']))

        diffarcsec1.append(np.degrees(diff) * 3600.)

        # FK4 to Galactic
        c1 = FK4(ra=r['lon_in']*u.deg, dec=r['lat_in']*u.deg,
                 obstime=Time(r['obstime'], scale='utc'),
                 equinox=Time(r['equinox_fk4'], scale='utc'))
        c2 = c1.transform_to(Galactic)

        # Find difference
        diff = angular_separation(c2.l.radian, c2.b.radian,
                                  np.radians(r['lon_gal']),
                                  np.radians(r['lat_gal']))

        diffarcsec2.append(np.degrees(diff) * 3600.)

    np.testing.assert_array_less(diffarcsec1, TOLERANCE)
    np.testing.assert_array_less(diffarcsec2, TOLERANCE)
Beispiel #45
0
	def compute_angletosun(self, meteo):
		"""
		Computes the distance to the Sun

		:param meteo: a Meteo object, whose time attribute has been actualized beforehand
		"""
		if SETTINGS["misc"]["singletargetlogs"] == "True":
			logger.debug("Computing angletosun for {}...".format(self.name))
		sunalt, sunaz = meteo.sunalt, meteo.sunaz
		alt, az = self.altitude, self.azimuth
		separation = angle_utilities.angular_separation(sunaz, sunalt, az, alt) # Warning, separation is in radian!!

		angletosun = angles.Angle(separation.value, unit="radian")
		self.angletosun = angletosun
def test_angsep():
    """
    Tests that the angular separation object also behaves correctly.
    """
    from astropy.coordinates.angle_utilities import angular_separation

    # check it both works with floats in radians, Quantities, or Angles
    for conv in (np.deg2rad,
                 lambda x: u.Quantity(x, "deg"),
                 lambda x: Angle(x, "deg")):
        for (lon1, lat1, lon2, lat2), corrsep in zip(coords, correct_seps):
            angsep = angular_separation(conv(lon1), conv(lat1),
                                        conv(lon2), conv(lat2))
            assert np.fabs(angsep - conv(corrsep)) < conv(correctness_margin)
Beispiel #47
0
    def evaluate(lon, lat, lon_0, lat_0, radius, width):
        """Evaluate the model (static function)."""
        sep = angular_separation(lon, lat, lon_0, lat_0)
        radius_out = radius + width

        norm = 3 / (2 * np.pi * (radius_out ** 3 - radius ** 3))

        with np.errstate(invalid="ignore"):
            # np.where and np.select do not work with quantities, so we use the
            # workaround with indexing
            value = np.sqrt(radius_out ** 2 - sep ** 2)
            mask = [sep < radius]
            value[mask] = (value - np.sqrt(radius ** 2 - sep ** 2))[mask]
            value[sep > radius_out] = 0

        return norm * value
Beispiel #48
0
def _compute_kernel_separations(geom, factor):
    # utility function used for preparing distance to the center of the upsampled geom
    # TODO : take into account non regular geometry for energy dependent PSF kernel size
    if geom.is_regular is False:
        raise ValueError("Non regular geometries are not supported yet.")

    upsampled_image_geom = geom.to_image().upsample(factor)
    # get center coordinate
    center_coord = upsampled_image_geom.center_coord * u.deg
    # get coordinates
    map_c = upsampled_image_geom.get_coord()
    # compute distances to map center
    separations = angular_separation(
        center_coord[0], center_coord[1], map_c.lon * u.deg, map_c.lat * u.deg
    )

    # Create map
    kernel_map = Map.from_geom(geom=upsampled_image_geom.to_cube(axes=geom.axes))
    return kernel_map, separations
Beispiel #49
0
	def compute_angletowind(self, meteo):
		"""
		Computes the angle to wind

		:param meteo: a Meteo object, whose time attribute has been actualized beforehand
		"""
		if SETTINGS["misc"]["singletargetlogs"] == "True":
			logger.debug("Computing angletowind for {}...".format(self.name))
		winddirection = meteo.winddirection
		if winddirection < 0 or winddirection > 360:
			self.angletowind = None
			return
		
		try:
			winddirection = angles.Angle(winddirection, unit='degree')
			self.angletowind = angle_utilities.angular_separation(winddirection, 0., self.azimuth, 0.)
			self.angletowind = angles.Angle(self.angletowind, unit="radian")
		except AttributeError:
			logger.error("{} has no azimuth! \n Compute its azimuth first !".format(self.name))
			raise AttributeError("%s has no azimuth! \n Compute its azimuth first !")
Beispiel #50
0
def anglesep(lon0: float, lat0: float,
             lon1: float, lat1: float, deg: bool = True) -> float:
    """
    Parameters
    ----------

    lon0 : float
        longitude of first point
    lat0 : float
        latitude of first point
    lon1 : float
        longitude of second point
    lat1 : float
        latitude of second point
    deg : bool, optional
          degrees input/output  (False: radians in/out)

    Returns
    -------

    sep_rad : float or numpy.ndarray of float
        angular separation

    For reference, this is from astropy astropy/coordinates/angle_utilities.py
    Angular separation between two points on a sphere.
    """
    if angular_separation is None:
        raise ImportError('angledist requires AstroPy. Try angledis_meeus')

    if deg:
        lon0 = radians(lon0)
        lat0 = radians(lat0)
        lon1 = radians(lon1)
        lat1 = radians(lat1)

    sep_rad = angular_separation(lon0, lat0, lon1, lat1)

    if deg:
        return degrees(sep_rad)
    else:
        return sep_rad
Beispiel #51
0
def pair_correlation(lon, lat, theta_bins):
    """Compute pair correlation function for points on the sphere.

    Parameters
    ----------
    lon, lat : array_like
        Coordinate arrays
    theta_bins : array_like
        Array defining the ``theta`` binning.
        ``theta`` is the angular offset between positions.
    unit : {'deg', 'rad'}
        Units of input and output coordinates

    Returns
    -------
    counts : array
        Array of point separations per ``theta`` bin.
    """
    separation = angular_separation(lon[:, np.newaxis], lat[:, np.newaxis], lon, lat)
    pair_correlation, _ = np.histogram(separation.ravel(), theta_bins)
    return pair_correlation
Beispiel #52
0
def minimum_separation(lon1, lat1, lon2, lat2):
    """Compute minimum distance of each (lon1, lat1) to any (lon2, lat2).

    Parameters
    ----------
    lon1, lat1 : array_like
        Primary coordinates of interest
    lon2, lat2 : array_like
        Counterpart coordinate array
    unit : {'deg', 'rad'}
        Units of input and output coordinates

    Returns
    -------
    theta_min : array
        Minimum distance
    """
    lon1 = np.asanyarray(lon1)
    lat1 = np.asanyarray(lat1)
    separation = angular_separation(
        lon1[:, np.newaxis], lat1[:, np.newaxis], lon2, lat2
    )
    return separation.min(axis=1)
Beispiel #53
0
def get_lon_lat_path(ax, transform, lon_lat):
    """
    Draw a curve, taking into account discontinuities.

    Parameters
    ----------
    ax : ~matplotlib.axes.Axes
        The axes in which to plot the grid
    transform : transformation class
        The transformation between the world and pixel coordinates
    lon_lat : `~numpy.ndarray`
        The longitude and latitude values along the curve, given as a (n,2)
        array.
    """

    # Get pixel limits
    # xlim = ax.get_xlim()
    # ylim = ax.get_ylim()

    # Transform line to pixel coordinates
    pixel = transform.transform(lon_lat)

    # In some spherical projections, some parts of the curve are 'behind' or
    # 'in front of' the plane of the image, so we find those by reversing the
    # transformation and finding points where the result is not consistent.

    lon_lat_check = transform.inverted().transform(pixel)

    sep = angular_separation(np.radians(lon_lat[:, 0]),
                             np.radians(lon_lat[:, 1]),
                             np.radians(lon_lat_check[:, 0]),
                             np.radians(lon_lat_check[:, 1]))

    sep[sep > np.pi] -= 2. * np.pi

    mask = np.abs(sep > ROUND_TRIP_TOL)

    # Mask values with invalid pixel positions
    mask = mask | np.isnan(pixel[:, 0]) | np.isnan(pixel[:, 1])

    # Mask values outside the viewport
    # This has now been disabled because it assumes specifically rectangular
    # axes, and also doesn't work if the coordinate direction is flipped.
    # outside = ((pixel[:, 0] < xlim[0]) | (pixel[:, 0] > xlim[-1]) |
    #            (pixel[:, 1] < ylim[0]) | (pixel[:, 1] > ylim[-1]))
    # mask[1:-1] = mask[1:-1] | (outside[2:] & outside[:-2])

    # We can now start to set up the codes for the Path.
    codes = np.zeros(lon_lat.shape[0], dtype=np.uint8)
    codes[:] = Path.LINETO
    codes[0] = Path.MOVETO
    codes[mask] = Path.MOVETO

    # Also need to move to point *after* a hidden value
    codes[1:][mask[:-1]] = Path.MOVETO

    # We now go through and search for discontinuities in the curve that would
    # be due to the curve going outside the field of view, invalid WCS values,
    # or due to discontinuities in the projection.

    # We start off by pre-computing the step in pixel coordinates from one
    # point to the next. The idea is to look for large jumps that might indicate
    # discontinuities.
    step = np.sqrt((pixel[1:, 0] - pixel[:-1, 0]) ** 2 +
                   (pixel[1:, 1] - pixel[:-1, 1]) ** 2)

    # We search for discontinuities by looking for places where the step
    # is larger by more than a given factor compared to the median
    # discontinuous = step > DISCONT_FACTOR * np.median(step)
    discontinuous = step[1:] > DISCONT_FACTOR * step[:-1]

    # Skip over discontinuities
    codes[2:][discontinuous] = Path.MOVETO

    # The above missed the first step, so check that too
    if step[0] > DISCONT_FACTOR * step[1]:
        codes[1] = Path.MOVETO

    # Create the path
    path = Path(pixel, codes=codes)

    # And add to the axes
    return path
Beispiel #54
0
def get_lon_lat_path(lon_lat, pixel, lon_lat_check):
    """
    Draw a curve, taking into account discontinuities.

    Parameters
    ----------
    lon_lat : `~numpy.ndarray`
        The longitude and latitude values along the curve, given as a (n,2)
        array.
    pixel : `~numpy.ndarray`
        The pixel coordinates corresponding to ``lon_lat``
    lon_lat : `~numpy.ndarray`
        The world coordinates derived from converting from ``pixel``, which is
        used to ensure round-tripping.
    """

    # In some spherical projections, some parts of the curve are 'behind' or
    # 'in front of' the plane of the image, so we find those by reversing the
    # transformation and finding points where the result is not consistent.

    sep = angular_separation(np.radians(lon_lat[:, 0]),
                             np.radians(lon_lat[:, 1]),
                             np.radians(lon_lat_check[:, 0]),
                             np.radians(lon_lat_check[:, 1]))

    sep[sep > np.pi] -= 2. * np.pi

    mask = np.abs(sep > ROUND_TRIP_TOL)

    # Mask values with invalid pixel positions
    mask = mask | np.isnan(pixel[:, 0]) | np.isnan(pixel[:, 1])

    # We can now start to set up the codes for the Path.
    codes = np.zeros(lon_lat.shape[0], dtype=np.uint8)
    codes[:] = Path.LINETO
    codes[0] = Path.MOVETO
    codes[mask] = Path.MOVETO

    # Also need to move to point *after* a hidden value
    codes[1:][mask[:-1]] = Path.MOVETO

    # We now go through and search for discontinuities in the curve that would
    # be due to the curve going outside the field of view, invalid WCS values,
    # or due to discontinuities in the projection.

    # We start off by pre-computing the step in pixel coordinates from one
    # point to the next. The idea is to look for large jumps that might indicate
    # discontinuities.
    step = np.sqrt((pixel[1:, 0] - pixel[:-1, 0]) ** 2 +
                   (pixel[1:, 1] - pixel[:-1, 1]) ** 2)

    # We search for discontinuities by looking for places where the step
    # is larger by more than a given factor compared to the median
    # discontinuous = step > DISCONT_FACTOR * np.median(step)
    discontinuous = step[1:] > DISCONT_FACTOR * step[:-1]

    # Skip over discontinuities
    codes[2:][discontinuous] = Path.MOVETO

    # The above missed the first step, so check that too
    if step[0] > DISCONT_FACTOR * step[1]:
        codes[1] = Path.MOVETO

    # Create the path
    path = Path(pixel, codes=codes)

    return path
Beispiel #55
0
    def _pix_size(self):
        """
        Return the size of each pixel along each direction, in world units

        Returns
        -------
        dv, dy, dx : tuple of 3D arrays

        The extent of each pixel along each direction

        Notes
        -----
        These arrays are broadcast, and are not memory intensive

        Each array is in the units of the corresponding wcs.cunit, but
        this is implicit (e.g., they are not astropy Quantity arrays)
        """

        # First, scale along x direction

        xpix = np.linspace(-0.5, self._data.shape[2] - 0.5, self._data.shape[2] + 1)
        ypix = np.linspace(0., self._data.shape[1] - 1, self._data.shape[1])
        xpix, ypix = np.meshgrid(xpix, ypix)
        zpix = np.zeros(xpix.shape)

        lon, lat, _ = self._wcs.all_pix2world(xpix, ypix, zpix, 0)

        # Convert to radians
        lon = np.radians(lon)
        lat = np.radians(lat)

        # Find the dx and dy arrays
        from astropy.coordinates.angle_utilities import angular_separation
        dx = angular_separation(lon[:, :-1], lat[:, :-1],
                                lon[:, 1:], lat[:, :-1])

        # Next, scale along y direction

        xpix = np.linspace(0., self._data.shape[2] - 1, self._data.shape[2])
        ypix = np.linspace(-0.5,
                           self._data.shape[1] - 0.5,
                           self._data.shape[1] + 1)
        xpix, ypix = np.meshgrid(xpix, ypix)
        zpix = np.zeros(xpix.shape)

        lon, lat, _ = self._wcs.all_pix2world(xpix, ypix, zpix, 0)

        # Convert to radians
        lon = np.radians(lon)
        lat = np.radians(lat)

        # Find the dx and dy arrays
        from astropy.coordinates.angle_utilities import angular_separation
        dy = angular_separation(lon[:-1, :], lat[:-1, :],
                                lon[1:, :], lat[1:, :])

        # Next, spectral coordinates
        zpix = np.linspace(-0.5, self._data.shape[0] - 0.5,
                           self._data.shape[0] + 1)
        xpix = np.zeros(zpix.shape)
        ypix = np.zeros(zpix.shape)

        _, _, spectral = self._wcs.all_pix2world(xpix, ypix, zpix, 0)

        dspectral = np.diff(spectral)

        dx = np.abs(np.degrees(dx.reshape(1, dx.shape[0], dx.shape[1])))
        dy = np.abs(np.degrees(dy.reshape(1, dy.shape[0], dy.shape[1])))
        dspectral = np.abs(dspectral.reshape(-1, 1, 1))
        dx, dy, dspectral = np.broadcast_arrays(dx, dy, dspectral)

        return dspectral, dy, dx
Beispiel #56
0
 def diag_size(self):
     """return the largest diagonal size"""
     p1,p2,p3,p4 = self.calc_footprint()
     return np.max([angular_separation(*np.concatenate([p1,p3])),
                    angular_separation(*np.concatenate([p2,p4]))])
Beispiel #57
0
        # It fails for empty pixels
        try:
            hillas_params[tel_id] = hillas_parameters(camgeom, cleaned_image)
        except:
            pass

    if len(hillas_params) < 2:
        continue

    reco_result = reco.predict(hillas_params, event.inst, point_altitude, point_azimuth)

    # get angular offset between reconstructed shower direction and MC
    # generated shower direction
    off_angle = angular_separation(
        event.mc.az,
        event.mc.alt,
        reco_result.az,
        reco_result.alt
    )

    # Appending all estimated off angles
    off_angles.append(off_angle.to(u.deg).value)

# calculate theta square for angles which are not nan
off_angles = np.array(off_angles)
thetasquare = off_angles[np.isfinite(off_angles)]**2

# To plot thetasquare The number of events in th data files for LSTCam is not
#  significantly high to give a nice thetasquare plot for gammas One can use
# deedicated MC file for LST get nice plot
plt.figure(figsize=(10, 8))
plt.hist(thetasquare, bins=np.linspace(0, 1, 50))
# assume the location of the centroids to be the published value
# draw values from 4 normal distribution
centroid_old = [[NW_cent.ra.deg, NW_cent.dec.deg, 0.87,
                SE_cent.ra.deg, SE_cent.dec.deg, 0.87]] * no

# hopefully that the arrays shape will be broadcast
N_halos = [2] * no
centroid_steps = [1. / np.sqrt(2) / 60. / 60.] * no
cent_new = map(get_new_centroids, N_halos, centroid_old, centroid_steps)
cent_new = np.array(cent_new)
[NW_ra, NW_dec, NW_z, SE_ra, SE_dec, SE_z] = cent_new.transpose()

# inputs of angular separation has to be in units of radians
ang_sep = \
    ang_util.angular_separation(NW_ra / 180. * np.pi,
                                NW_dec / 180. * np.pi,
                                SE_ra / 180. * np.pi,
                                SE_dec / 180. * np.pi)
cosmo = FlatLambdaCDM(H0=70, Om0=0.3)
D_proj = cosmo.angular_diameter_distance(0.87) * ang_sep


###
# Debug input
###

def plot_dproj():
    plt.title('D-proj')
    plt.xlabel('Mpc')
    plt.hist(D_proj, bins=100, normed=True, histtype='step')
    plt.savefig(out_prefix + '_D_proj.png')
    plt.close()