Exemplo n.º 1
0
class HorizonFrame(BaseCoordinateFrame):
    """Horizon coordinate frame. Spherical system used to describe the direction
    of a given position, in terms of the altitude and azimuth of the system. In
    practice this is functionally identical as the astropy AltAz system, but this
    implementation allows us to pass array pointing information, allowing us to directly
    transform to the Horizon Frame from the Camera system.
    The Following attributes are carried over from the telescope frame
    to allow a direct transformation from the camera frame

    Frame attributes:

    * ``array_direction``
        Alt,Az direction of the array pointing
    * ``pointing_direction``
        Alt,Az direction of the telescope pointing

    """
    default_representation = UnitSphericalRepresentation

    frame_specific_representation_info = {
        'spherical': [
            RepresentationMapping('lon', 'az'),
            RepresentationMapping('lat', 'alt')
        ],
    }

    frame_specific_representation_info[
        'unitspherical'] = frame_specific_representation_info['spherical']

    pointing_direction = Attribute(default=None)
    array_direction = Attribute(default=None)
Exemplo n.º 2
0
class CameraFrame(BaseCoordinateFrame):
    '''
    Astropy CoordinateFrame representing coordinates in the CameraPlane

    Attributes
    ----------
    pointing_direction: astropy.coordinates.AltAz
        The pointing direction of the telescope
    obstime: astropy.Time
        The timestamp of the observation, only needed to directly transform
        to Equatorial coordinates, transforming to AltAz does not need this.
    location: astropy.coordinates.EarthLocation
        The location of the observer,  only needed to directly transform
        to Equatorial coordinates, transforming to AltAz does not need this,
        default is FACT's location
    rotated: bool
        True means x points right and y points up when looking on the camera
        from the dish, which is the efinition of FACT-Tools >= 1.0 and Mars.
        False means x points up and y points left,
        which is definition in the original FACTPixelMap file.
    '''
    default_representation = PlanarRepresentation
    pointing_direction = CoordinateAttribute(frame=AltAz, default=None)
    obstime = TimeAttribute(default=None)
    location = EarthLocationAttribute(default=LOCATION)
    rotated = Attribute(default=True)
Exemplo n.º 3
0
class CameraFrame(BaseCoordinateFrame):
    """Camera coordinate frame.  The camera frame is a simple physical
    cartesian frame, describing the 2 dimensional position of objects
    in the focal plane of the telescope Most Typically this will be
    used to describe the positions of the pixels in the focal plane

    Frame attributes:

    * ``focal_length``
        Focal length of the telescope as a unit quantity (usually meters)
    * ``rotation``
        Rotation angle of the camera (0 deg in most cases)
    """
    default_representation = PlanarRepresentation
    focal_length = Attribute(default=None)
    rotation = Attribute(default=0 * u.deg)
    pointing_direction = Attribute(default=None)
    array_direction = Attribute(default=None)
Exemplo n.º 4
0
class NominalFrame(BaseCoordinateFrame):
    """Nominal coordinate frame.  Cartesian system to describe the angular
    offset of a given position in reference to pointing direction of a
    nominal array pointing position. In most cases this frame is the
    same as the telescope frame, however in the case of divergent
    pointing they will differ.  Event reconstruction should be
    performed in this system

    Frame attributes:

    * ``array_direction``
        Alt,Az direction of the array pointing
    * ``pointing_direction``
        Alt,Az direction of the telescope pointing

    """
    default_representation = PlanarRepresentation
    pointing_direction = Attribute(default=None)
    array_direction = Attribute(default=None)
Exemplo n.º 5
0
class GroundFrame(BaseCoordinateFrame):
    """Ground coordinate frame.  The ground coordinate frame is a simple
    cartesian frame describing the 3 dimensional position of objects
    compared to the array ground level in relation to the nomial
    centre of the array.  Typically this frame will be used for
    describing the position on telescopes and equipment

    Frame attributes: None

    """
    default_representation = CartesianRepresentation
    # Pointing direction of the tilted system (alt,az),
    # could be the telescope pointing direction or the reconstructed shower
    # direction
    pointing_direction = Attribute(default=None)
Exemplo n.º 6
0
class TiltedGroundFrame(BaseCoordinateFrame):
    """Tilted ground coordinate frame.  The tilted ground coordinate frame
    is a cartesian system describing the 2 dimensional projected
    positions of objects in a tilted plane described by
    pointing_direction Typically this frame will be used for the
    reconstruction of the shower core position

    Frame attributes:
    
    * ``pointing_direction``
        Alt,Az direction of the tilted reference plane

    """
    default_representation = PlanarRepresentation
    # Pointing direction of the tilted system (alt,az),
    # could be the telescope pointing direction or the reconstructed shower
    # direction
    pointing_direction = Attribute(default=None)
Exemplo n.º 7
0
class TelescopeFrame(BaseCoordinateFrame):
    """Telescope coordinate frame.  Cartesian system to describe the
    angular offset of a given position in reference to pointing
    direction of a given telescope When pointing corrections become
    available they should be applied to the transformation between
    this frame and the camera frame

    Frame attributes:

    * ``focal_length``
        Focal length of the telescope as a unit quantity (usually meters)
    * ``rotation``
        Rotation angle of the camera (0 deg in most cases)
    * ``pointing_direction``
        Alt,Az direction of the telescope pointing

    """
    default_representation = PlanarRepresentation
    pointing_direction = Attribute(default=None)
Exemplo n.º 8
0
class SPIFrame(BaseCoordinateFrame):
    """
    
    INTEGRAL SPI Frame
    Parameters
    ----------
    representation : `BaseRepresentation` or None
        A representation object or None to have no data (or use the other keywords)
  
    """
    default_representation = coord.SphericalRepresentation

    frame_specific_representation_info = {
        'spherical': [
            RepresentationMapping(reprname='lon',
                                  framename='lon',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='lat',
                                  framename='lat',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='distance',
                                  framename='DIST',
                                  defaultunit=None)
        ],
        'unitspherical': [
            RepresentationMapping(reprname='lon',
                                  framename='lon',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='lat',
                                  framename='lat',
                                  defaultunit=u.degree)
        ],
        'cartesian': [
            RepresentationMapping(reprname='x', framename='SCX'),
            RepresentationMapping(reprname='y', framename='SCY'),
            RepresentationMapping(reprname='z', framename='SCZ')
        ]
    }

    # Specify frame attributes required to fully specify the frame
    scx_ra = Attribute(default=None)
    scx_dec = Attribute(default=None)

    scy_ra = Attribute(default=None)
    scy_dec = Attribute(default=None)

    scz_ra = Attribute(default=None)
    scz_dec = Attribute(default=None)
Exemplo n.º 9
0
class GBMFrame(BaseCoordinateFrame):
    """
    
    Fermi GBM Frame

    Parameters
    ----------
    representation : `BaseRepresentation` or None
        A representation object or None to have no data (or use the other keywords)
  
    """

    default_representation = coord.SphericalRepresentation

    frame_specific_representation_info = {
        "spherical": [
            RepresentationMapping(reprname="lon",
                                  framename="lon",
                                  defaultunit=u.degree),
            RepresentationMapping(reprname="lat",
                                  framename="lat",
                                  defaultunit=u.degree),
            RepresentationMapping(reprname="distance",
                                  framename="DIST",
                                  defaultunit=None),
        ],
        "unitspherical": [
            RepresentationMapping(reprname="lon",
                                  framename="lon",
                                  defaultunit=u.degree),
            RepresentationMapping(reprname="lat",
                                  framename="lat",
                                  defaultunit=u.degree),
        ],
        "cartesian": [
            RepresentationMapping(reprname="x", framename="SCX"),
            RepresentationMapping(reprname="y", framename="SCY"),
            RepresentationMapping(reprname="z", framename="SCZ"),
        ],
    }

    # Specify frame attributes required to fully specify the frame
    sc_pos_X = Attribute(default=None)
    sc_pos_Y = Attribute(default=None)
    sc_pos_Z = Attribute(default=None)

    quaternion_1 = Attribute(default=None)
    quaternion_2 = Attribute(default=None)
    quaternion_3 = Attribute(default=None)
    quaternion_4 = Attribute(default=None)

    # equinox = TimeFrameAttribute(default='J2000')

    @staticmethod
    def _set_quaternion(q1, q2, q3, q4):
        sc_matrix = np.zeros((3, 3))

        sc_matrix[0, 0] = q1**2 - q2**2 - q3**2 + q4**2
        sc_matrix[0, 1] = 2.0 * (q1 * q2 + q4 * q3)
        sc_matrix[0, 2] = 2.0 * (q1 * q3 - q4 * q2)
        sc_matrix[1, 0] = 2.0 * (q1 * q2 - q4 * q3)
        sc_matrix[1, 1] = -(q1**2) + q2**2 - q3**2 + q4**2
        sc_matrix[1, 2] = 2.0 * (q2 * q3 + q4 * q1)
        sc_matrix[2, 0] = 2.0 * (q1 * q3 + q4 * q2)
        sc_matrix[2, 1] = 2.0 * (q2 * q3 - q4 * q1)
        sc_matrix[2, 2] = -(q1**2) - q2**2 + q3**2 + q4**2

        return sc_matrix
Exemplo n.º 10
0
class Helioprojective(BaseCoordinateFrame):
    """
    A coordinate or frame in the Helioprojective (Cartesian) system.

    This is a projective coordinate system centered around the observer.
    It is a full spherical coordinate system with position given as longitude
    theta_x and latitude theta_y.

    Parameters
    ----------
    representation: `~astropy.coordinates.BaseRepresentation` or None.
        A representation object. If specified, other parameters must
        be in keyword form.
    Tx: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        X-axis coordinate.
    Ty: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        Y-axis coordinate.
    distance: `~astropy.units.Quantity`
        The radial distance from the observer to the coordinate point.
    obstime: SunPy Time
        The date and time of the observation, used to convert to heliographic
        carrington coordinates.
    observer: `~sunpy.coordinates.frames.HeliographicStonyhurst`
        The coordinate of the observer in the solar system.
    rsun: `~astropy.units.Quantity`
        The physical (length) radius of the Sun. Used to calculate the position
        of the limb for calculating distance from the observer to the
        coordinate.

    Examples
    --------
    >>> from astropy.coordinates import SkyCoord
    >>> import sunpy.coordinates
    >>> import astropy.units as u
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, 5*u.km, obstime="2010/01/01T00:00:00",
    ...               frame="helioprojective")
    >>> sc # doctest: +FLOAT_CMP
    <SkyCoord (Helioprojective: obstime=2010-01-01 00:00:00, rsun=695508.0 km, observer=<HeliographicStonyhurst Coordinate (obstime=2010-01-01 00:00:00): (lon, lat, radius) in (deg, deg, AU)
        ( 0., -3.00724817,  0.98330294)>): (Tx, Ty, distance) in (arcsec, arcsec, km)
        ( 0.,  0.,  5.)>
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, obstime="2010/01/01T00:00:00", frame="helioprojective")
    >>> sc # doctest: +FLOAT_CMP
    <SkyCoord (Helioprojective: obstime=2010-01-01 00:00:00, rsun=695508.0 km, observer=<HeliographicStonyhurst Coordinate (obstime=2010-01-01 00:00:00): (lon, lat, radius) in (deg, deg, AU)
        ( 0., -3.00724817,  0.98330294)>): (Tx, Ty) in arcsec
        ( 0.,  0.)>
    """

    default_representation = SphericalRepresentation

    frame_specific_representation_info = {
        SphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='distance',
                                  framename='distance',
                                  defaultunit=None)
        ],
        UnitSphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec)
        ],
    }

    obstime = TimeFrameAttributeSunPy()
    rsun = Attribute(default=RSUN_METERS.to(u.km))
    observer = ObserverCoordinateAttribute(HeliographicStonyhurst,
                                           default="earth")

    def __init__(self, *args, **kwargs):
        wrap = kwargs.pop('wrap_longitude', True)

        BaseCoordinateFrame.__init__(self, *args, **kwargs)

        if wrap and isinstance(
                self._data,
            (UnitSphericalRepresentation, SphericalRepresentation)):
            self._data.lon.wrap_angle = 180 * u.deg

    def calculate_distance(self):
        """
        This method calculates the third coordinate of the Helioprojective
        frame. It assumes that the coordinate point is on the disk of the Sun
        at the rsun radius.

        If a point in the frame is off limb then NaN will be returned.

        Returns
        -------
        new_frame : `~sunpy.coordinates.frames.HelioProjective`
            A new frame instance with all the attributes of the original but
            now with a third coordinate.
        """
        # Skip if we already are 3D
        if (isinstance(self._data, SphericalRepresentation)
                and not (self.distance.unit is u.one
                         and quantity_allclose(self.distance, 1 * u.one))):
            return self

        if not isinstance(self.observer, BaseCoordinateFrame):
            raise ConvertError("Cannot calculate distance to the solar disk "
                               "for observer '{}' "
                               "without `obstime` being specified.".format(
                                   self.observer))

        rep = self.represent_as(UnitSphericalRepresentation)
        lat, lon = rep.lat, rep.lon
        alpha = np.arccos(np.cos(lat) * np.cos(lon)).to(lat.unit)
        c = self.observer.radius**2 - self.rsun**2
        b = -2 * self.observer.radius * np.cos(alpha)
        d = ((-1 * b) - np.sqrt(b**2 - 4 * c)) / 2

        return self.realize_frame(
            SphericalRepresentation(lon=lon, lat=lat, distance=d))
Exemplo n.º 11
0
class GBMFrame(BaseCoordinateFrame):
    """
    
    Fermi GBM Frame

    Parameters
    ----------
    representation : `BaseRepresentation` or None
        A representation object or None to have no data (or use the other keywords)
  
    """
    default_representation = coord.SphericalRepresentation

    frame_specific_representation_info = {
        'spherical': [
            RepresentationMapping(reprname='lon',
                                  framename='lon',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='lat',
                                  framename='lat',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='distance',
                                  framename='DIST',
                                  defaultunit=None)
        ],
        'unitspherical': [
            RepresentationMapping(reprname='lon',
                                  framename='lon',
                                  defaultunit=u.degree),
            RepresentationMapping(reprname='lat',
                                  framename='lat',
                                  defaultunit=u.degree)
        ],
        'cartesian': [
            RepresentationMapping(reprname='x', framename='SCX'),
            RepresentationMapping(reprname='y', framename='SCY'),
            RepresentationMapping(reprname='z', framename='SCZ')
        ]
    }

    # Specify frame attributes required to fully specify the frame
    sc_pos_X = Attribute(default=None)
    sc_pos_Y = Attribute(default=None)
    sc_pos_Z = Attribute(default=None)

    quaternion_1 = Attribute(default=None)
    quaternion_2 = Attribute(default=None)
    quaternion_3 = Attribute(default=None)
    quaternion_4 = Attribute(default=None)

    # equinox = TimeFrameAttribute(default='J2000')

    @staticmethod
    def _set_quaternion(q1, q2, q3, q4):
        sc_matrix = np.zeros((3, 3))

        sc_matrix[0, 0] = (q1**2 - q2**2 - q3**2 + q4**2)
        sc_matrix[0, 1] = 2.0 * (q1 * q2 + q4 * q3)
        sc_matrix[0, 2] = 2.0 * (q1 * q3 - q4 * q2)
        sc_matrix[1, 0] = 2.0 * (q1 * q2 - q4 * q3)
        sc_matrix[1, 1] = (-q1**2 + q2**2 - q3**2 + q4**2)
        sc_matrix[1, 2] = 2.0 * (q2 * q3 + q4 * q1)
        sc_matrix[2, 0] = 2.0 * (q1 * q3 + q4 * q2)
        sc_matrix[2, 1] = 2.0 * (q2 * q3 - q4 * q1)
        sc_matrix[2, 2] = (-q1**2 - q2**2 + q3**2 + q4**2)

        return sc_matrix
Exemplo n.º 12
0
class Helioprojective(SunPyBaseCoordinateFrame):
    """
    A coordinate or frame in the Helioprojective Cartesian (HPC) system, which is observer-based.

    - The origin is the location of the observer.
    - ``theta_x`` is the angle relative to the plane containing the Sun-observer line and the Sun's
      rotation axis, with positive values in the direction of the Sun's west limb.
    - ``theta_y`` is the angle relative to the Sun's equatorial plane, with positive values in the
      direction of the Sun's north pole.
    - ``distance`` is the Sun-observer distance.

    This system is frequently used in a projective form without ``distance`` specified.  For
    observations looking very close to the center of the Sun, where the small-angle approximation
    is appropriate, ``theta_x`` and ``theta_y`` can be approximated as Cartesian components.

    A new instance can be created using the following signatures
    (note that if supplied, ``obstime`` and ``observer`` must be keyword arguments)::

        Helioprojective(theta_x, theta_y, obstime=obstime, observer=observer)
        Helioprojective(theta_x, theta_y, distance, obstime=obstime, observer=observer)

    Parameters
    ----------
    {data}
    Tx : `~astropy.coordinates.Angle` or `~astropy.units.Quantity`
        The theta_x coordinate for this object. Not needed if ``data`` is given.
    Ty : `~astropy.coordinates.Angle` or `~astropy.units.Quantity`
        The theta_y coordinate for this object. Not needed if ``data`` is given.
    distance : `~astropy.units.Quantity`
        The distance coordinate from the observer for this object.
        Not needed if ``data`` is given.
    {observer}
    rsun : `~astropy.units.Quantity`
        The physical (length) radius of the Sun. Used to calculate the position
        of the limb for calculating distance from the observer to the
        coordinate. Defaults to the solar radius.
    {common}

    Examples
    --------
    >>> from astropy.coordinates import SkyCoord
    >>> import sunpy.coordinates
    >>> import astropy.units as u
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, 5*u.km,
    ...               obstime="2010/01/01T00:00:00", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, km)
        (0., 0., 5.)>
    >>> sc = SkyCoord(0*u.deg, 0*u.deg,
    ...               obstime="2010/01/01T00:00:00", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty) in arcsec
        (0., 0.)>
    >>> sc = SkyCoord(CartesianRepresentation(1*u.AU, 1e5*u.km, -2e5*u.km),
    ...               obstime="2011/01/05T00:00:50", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2011-01-05T00:00:50.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, AU)
        (137.87948623, -275.75878762, 1.00000112)>
    """
    default_representation = SphericalRepresentation

    frame_specific_representation_info = {
        SphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='distance',
                                  framename='distance',
                                  defaultunit=None)
        ],
        UnitSphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec)
        ],
    }

    rsun = Attribute(default=_RSUN.to(u.km))
    observer = ObserverCoordinateAttribute(HeliographicStonyhurst)

    def make_3d(self):
        """
        This method calculates the third coordinate of the Helioprojective
        frame. It assumes that the coordinate point is on the surface of the Sun.

        If a point in the frame is off limb then NaN will be returned.

        Returns
        -------
        new_frame : `~sunpy.coordinates.frames.Helioprojective`
            A new frame instance with all the attributes of the original but
            now with a third coordinate.
        """
        # Skip if we already are 3D
        distance = self.spherical.distance
        if not (distance.unit is u.one and u.allclose(distance, 1 * u.one)):
            return self

        if not isinstance(self.observer, BaseCoordinateFrame):
            raise ConvertError("Cannot calculate distance to the Sun "
                               f"for observer '{self.observer}' "
                               "without `obstime` being specified.")

        rep = self.represent_as(UnitSphericalRepresentation)
        lat, lon = rep.lat, rep.lon
        alpha = np.arccos(np.cos(lat) * np.cos(lon)).to(lat.unit)
        c = self.observer.radius**2 - self.rsun**2
        b = -2 * self.observer.radius * np.cos(alpha)
        # Ingore sqrt of NaNs
        with np.errstate(invalid='ignore'):
            d = ((-1 * b) - np.sqrt(b**2 - 4 * c)) / 2

        return self.realize_frame(
            SphericalRepresentation(lon=lon, lat=lat, distance=d))

    # Support the previous name for make_3d for now
    calculate_distance = deprecated('1.1',
                                    name="calculate_distance",
                                    alternative="make_3d")(make_3d)
Exemplo n.º 13
0
class Helioprojective(SunPyBaseCoordinateFrame):
    """
    A coordinate or frame in the Helioprojective Cartesian (HPC) system, which is observer-based.

    - The origin is the location of the observer.
    - ``Tx`` (aka "theta_x") is the angle relative to the plane containing the Sun-observer line
      and the Sun's rotation axis, with positive values in the direction of the Sun's west limb.
    - ``Ty`` (aka "theta_y") is the angle relative to the Sun's equatorial plane, with positive
      values in the direction of the Sun's north pole.
    - ``distance`` is the Sun-observer distance.

    This system is frequently used in a projective form without ``distance`` specified.  For
    observations looking very close to the center of the Sun, where the small-angle approximation
    is appropriate, ``Tx`` and ``Ty`` can be approximated as Cartesian components.

    A new instance can be created using the following signatures
    (note that if supplied, ``obstime`` and ``observer`` must be keyword arguments)::

        Helioprojective(Tx, Ty, obstime=obstime, observer=observer)
        Helioprojective(Tx, Ty, distance, obstime=obstime, observer=observer)

    Parameters
    ----------
    {data}
    Tx : `~astropy.coordinates.Angle` or `~astropy.units.Quantity`
        The theta_x coordinate for this object. Not needed if ``data`` is given.
    Ty : `~astropy.coordinates.Angle` or `~astropy.units.Quantity`
        The theta_y coordinate for this object. Not needed if ``data`` is given.
    distance : `~astropy.units.Quantity`
        The distance coordinate from the observer for this object.
        Not needed if ``data`` is given.
    {observer}
    rsun : `~astropy.units.Quantity`
        The physical (length) radius of the Sun. Used to calculate the position
        of the limb for calculating distance from the observer to the
        coordinate. Defaults to the solar radius.
    {common}

    Examples
    --------
    >>> from astropy.coordinates import SkyCoord
    >>> import sunpy.coordinates
    >>> import astropy.units as u
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, 5*u.km,
    ...               obstime="2010/01/01T00:00:00", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, km)
        (0., 0., 5.)>
    >>> sc = SkyCoord(0*u.deg, 0*u.deg,
    ...               obstime="2010/01/01T00:00:00", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty) in arcsec
        (0., 0.)>
    >>> sc = SkyCoord(CartesianRepresentation(1*u.AU, 1e5*u.km, -2e5*u.km),
    ...               obstime="2011/01/05T00:00:50", observer="earth", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2011-01-05T00:00:50.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, AU)
        (137.87948623, -275.75878762, 1.00000112)>
    """
    frame_specific_representation_info = {
        SphericalRepresentation: [RepresentationMapping('lon', 'Tx', u.arcsec),
                                  RepresentationMapping('lat', 'Ty', u.arcsec),
                                  RepresentationMapping('distance', 'distance', None)],
        SphericalDifferential: [RepresentationMapping('d_lon', 'd_Tx', u.arcsec/u.s),
                                RepresentationMapping('d_lat', 'd_Ty', u.arcsec/u.s),
                                RepresentationMapping('d_distance', 'd_distance', u.km/u.s)],
        UnitSphericalRepresentation: [RepresentationMapping('lon', 'Tx', u.arcsec),
                                      RepresentationMapping('lat', 'Ty', u.arcsec)],
    }

    rsun = Attribute(default=_RSUN.to(u.km))
    observer = ObserverCoordinateAttribute(HeliographicStonyhurst)

    def make_3d(self):
        """
        This method calculates the third coordinate of the Helioprojective
        frame. It assumes that the coordinate point is on the surface of the Sun.

        If a point in the frame is off limb then NaN will be returned.

        Returns
        -------
        new_frame : `~sunpy.coordinates.frames.Helioprojective`
            A new frame instance with all the attributes of the original but
            now with a third coordinate.
        """
        # Skip if we already are 3D
        distance = self.spherical.distance
        if not (distance.unit is u.one and u.allclose(distance, 1*u.one)):
            return self

        if not isinstance(self.observer, BaseCoordinateFrame):
            raise ConvertError("Cannot calculate distance to the Sun "
                               f"for observer '{self.observer}' "
                               "without `obstime` being specified.")

        rep = self.represent_as(UnitSphericalRepresentation)
        lat, lon = rep.lat, rep.lon

        # Check for the use of floats with lower precision than the native Python float
        if not set([lon.dtype.type, lat.dtype.type]).issubset([float, np.float64, np.longdouble]):
            raise SunpyUserWarning("The Helioprojective component values appear to be lower "
                                   "precision than the native Python float: "
                                   f"Tx is {lon.dtype.name}, and Ty is {lat.dtype.name}. "
                                   "To minimize precision loss, you may want to cast the values to "
                                   "`float` or `numpy.float64` via the NumPy method `.astype()`.")

        # Calculate the distance to the surface of the Sun using the law of cosines
        cos_alpha = np.cos(lat) * np.cos(lon)
        c = self.observer.radius**2 - self.rsun**2
        b = -2 * self.observer.radius * cos_alpha
        # Ignore sqrt of NaNs
        with np.errstate(invalid='ignore'):
            d = ((-1*b) - np.sqrt(b**2 - 4*c)) / 2  # use the "near" solution

        if self._spherical_screen:
            sphere_center = self._spherical_screen['center'].transform_to(self).cartesian
            c = sphere_center.norm()**2 - self._spherical_screen['radius']**2
            b = -2 * sphere_center.dot(rep)
            # Ignore sqrt of NaNs
            with np.errstate(invalid='ignore'):
                dd = ((-1*b) + np.sqrt(b**2 - 4*c)) / 2  # use the "far" solution

            d = np.fmin(d, dd) if self._spherical_screen['only_off_disk'] else dd

        return self.realize_frame(SphericalRepresentation(lon=lon,
                                                          lat=lat,
                                                          distance=d))

    _spherical_screen = None

    @classmethod
    @contextmanager
    def assume_spherical_screen(cls, center, only_off_disk=False):
        """
        Context manager to interpret 2D coordinates as being on the inside of a spherical screen.

        The radius of the screen is the distance between the specified ``center`` and Sun center.
        This ``center`` does not have to be the same as the observer location for the coordinate
        frame.  If they are the same, then this context manager is equivalent to assuming that the
        helioprojective "zeta" component is zero.

        This replaces the default assumption where 2D coordinates are mapped onto the surface of the
        Sun.

        Parameters
        ----------
        center : `~astropy.coordinates.SkyCoord`
            The center of the spherical screen
        only_off_disk : `bool`, optional
            If `True`, apply this assumption only to off-disk coordinates, with on-disk coordinates
            still mapped onto the surface of the Sun.  Defaults to `False`.

        Examples
        --------

        .. minigallery:: sunpy.coordinates.Helioprojective.assume_spherical_screen

        >>> import astropy.units as u
        >>> from sunpy.coordinates import Helioprojective
        >>> h = Helioprojective(range(7)*u.arcsec*319, [0]*7*u.arcsec,
        ...                     observer='earth', obstime='2020-04-08')
        >>> print(h.make_3d())
        <Helioprojective Coordinate (obstime=2020-04-08T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, AU)
            [(   0., 0., 0.99660825), ( 319., 0., 0.99687244),
             ( 638., 0., 0.99778472), ( 957., 0., 1.00103285),
             (1276., 0.,        nan), (1595., 0.,        nan),
             (1914., 0.,        nan)]>

        >>> with Helioprojective.assume_spherical_screen(h.observer):
        ...     print(h.make_3d())
        <Helioprojective Coordinate (obstime=2020-04-08T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, AU)
            [(   0., 0., 1.00125872), ( 319., 0., 1.00125872),
             ( 638., 0., 1.00125872), ( 957., 0., 1.00125872),
             (1276., 0., 1.00125872), (1595., 0., 1.00125872),
             (1914., 0., 1.00125872)]>

        >>> with Helioprojective.assume_spherical_screen(h.observer, only_off_disk=True):
        ...     print(h.make_3d())
        <Helioprojective Coordinate (obstime=2020-04-08T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, AU)
            [(   0., 0., 0.99660825), ( 319., 0., 0.99687244),
             ( 638., 0., 0.99778472), ( 957., 0., 1.00103285),
             (1276., 0., 1.00125872), (1595., 0., 1.00125872),
             (1914., 0., 1.00125872)]>
        """
        try:
            old_spherical_screen = cls._spherical_screen  # nominally None

            center_hgs = center.transform_to(HeliographicStonyhurst(obstime=center.obstime))
            cls._spherical_screen = {
                'center': center,
                'radius': center_hgs.radius,
                'only_off_disk': only_off_disk
            }
            yield
        finally:
            cls._spherical_screen = old_spherical_screen
Exemplo n.º 14
0
class ENU(BaseCoordinateFrame):
    """Local geographic frames on the Earth, oriented along cardinal directions
    """

    default_representation = CartesianRepresentation
    """Default representation of local frames"""

    location = Attribute(default=None)
    """The origin on Earth of the local frame"""

    orientation = Attribute(default=("E", "N", "U"))
    """The orientation of the local frame, as cardinal directions"""

    magnetic = Attribute(default=False)
    """When enabled, use the magnetic North instead of the geographic one"""

    obstime = TimeAttribute(default=None)
    """The observation time"""
    def __init__(self,
                 *args,
                 location=None,
                 orientation=None,
                 magnetic=False,
                 obstime=None,
                 **kwargs):
        """Initialisation of a local frame

        Parameters
        ----------
        *args
            Any representation of the frame data, e.g. x, y, and z coordinates
        location : EarthLocation
            The location on Earth of the local frame origin
        orientation : sequence of str, optional
            The cardinal directions of the x, y, and z axis (default: E, N, U)
        magnetic : boolean, optional
            Use the magnetic north instead of the geographic one (default: false)
        obstime : Time or datetime or str, optional
            The observation time
        **kwargs
            Any extra BaseCoordinateFrame arguments

        Raises
        ------
        ValueError
            The local frame configuration is not valid
        """

        # Do the base initialisation
        location = self.location if location is None else location
        orientation = self.orientation if orientation is None else orientation

        super().__init__(*args,
                         location=location,
                         orientation=orientation,
                         magnetic=magnetic,
                         obstime=obstime,
                         **kwargs)

        # Set the transform parameters
        itrs = self._location.itrs
        geo = itrs.represent_as(GeodeticRepresentation)
        latitude, longitude = geo.latitude / u.deg, geo.longitude / u.deg

        if magnetic:
            # Compute the magnetic declination
            if self._obstime is None:
                raise ValueError("Magnetic coordinates require specifying "
                                 "an observation time")
            ecef = ECEF(itrs.x, itrs.y, itrs.z, obstime=self._obstime)

            if not _HAS_GEOMAGNET:
                from ..geomagnet import field as _geomagnetic_field
            field = _geomagnetic_field(ecef)

            c = field.cartesian
            c /= c.norm()
            h = c.represent_as(HorizontalRepresentation)
            azimuth0 = (h.azimuth / u.deg).value
        else:
            azimuth0 = 0.

        def vector(name):
            tag = name[0].upper()
            if tag == "E":
                return turtle.ecef_from_horizontal(latitude, longitude,
                                                   90 + azimuth0, 0)
            elif tag == "W":
                return turtle.ecef_from_horizontal(latitude, longitude,
                                                   270 + azimuth0, 0)
            elif tag == "N":
                return turtle.ecef_from_horizontal(latitude, longitude,
                                                   azimuth0, 0)
            elif tag == "S":
                return turtle.ecef_from_horizontal(latitude, longitude,
                                                   180 + azimuth0, 0)
            elif tag == "U":
                return turtle.ecef_from_horizontal(latitude, longitude, 0, 90)
            elif tag == "D":
                return turtle.ecef_from_horizontal(latitude, longitude, 0, -90)
            else:
                raise ValueError(f"Invalid frame orientation `{name}`")

        ux = vector(self._orientation[0])
        uy = vector(self._orientation[1])
        uz = vector(self._orientation[2])

        self._basis = numpy.column_stack((ux, uy, uz))
        self._origin = itrs.cartesian
Exemplo n.º 15
0
class Helioprojective(BaseCoordinateFrame):
    """
    A coordinate or frame in the Helioprojective (Cartesian) system.

    This is a projective coordinate system centered around the observer.
    It is a full spherical coordinate system with position given as longitude
    theta_x and latitude theta_y.

    Parameters
    ----------
    representation: `~astropy.coordinates.BaseRepresentation` or None.
        A representation object. If specified, other parameters must
        be in keyword form.
    Tx: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        X-axis coordinate.
    Ty: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        Y-axis coordinate.
    distance: `~astropy.units.Quantity`
        The radial distance from the observer to the coordinate point.
    obstime: SunPy Time
        The date and time of the observation, used to convert to heliographic
        carrington coordinates.
    observer: `~sunpy.coordinates.frames.HeliographicStonyhurst`
        The coordinate of the observer in the solar system.
    rsun: `~astropy.units.Quantity`
        The physical (length) radius of the Sun. Used to calculate the position
        of the limb for calculating distance from the observer to the
        coordinate.

    Examples
    --------
    >>> from astropy.coordinates import SkyCoord
    >>> import sunpy.coordinates
    >>> import astropy.units as u
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, 5*u.km, obstime="2010/01/01T00:00:00",
    ...               frame="helioprojective")
    >>> sc
    <SkyCoord (HelioProjective): obstime=2010-01-01 00:00:00, D0=149597870.7 km
    , Tx=0.0 arcsec, Ty=0.0 arcsec, distance=5.0 km>
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, obstime="2010/01/01T00:00:00",
    frame="helioprojective")
    >>> sc
    <SkyCoord (HelioProjective): obstime=2010-01-01 00:00:00, D0=149597870.7 km
    , Tx=0.0 arcsec, Ty=0.0 arcsec, distance=149597870.7 km>
    """

    default_representation = SphericalWrap180Representation

    _frame_specific_representation_info = {
        'spherical': [
            RepresentationMapping('lon', 'Tx', u.arcsec),
            RepresentationMapping('lat', 'Ty', u.arcsec),
            RepresentationMapping('distance', 'distance', u.km)
        ],
        'sphericalwrap180': [
            RepresentationMapping('lon', 'Tx', u.arcsec),
            RepresentationMapping('lat', 'Ty', u.arcsec),
            RepresentationMapping('distance', 'distance', u.km)
        ],
        'unitspherical': [
            RepresentationMapping('lon', 'Tx', u.arcsec),
            RepresentationMapping('lat', 'Ty', u.arcsec)
        ],
        'unitsphericalwrap180': [
            RepresentationMapping('lon', 'Tx', u.arcsec),
            RepresentationMapping('lat', 'Ty', u.arcsec)
        ]
    }

    obstime = TimeFrameAttributeSunPy()
    rsun = Attribute(default=RSUN_METERS.to(u.km))
    observer = ObserverCoordinateAttribute(HeliographicStonyhurst,
                                           default="earth")

    def __init__(self, *args, **kwargs):
        _rep_kwarg = kwargs.get('representation', None)

        BaseCoordinateFrame.__init__(self, *args, **kwargs)

        # Convert from Spherical to SphericalWrap180
        # If representation was explicitly passed, do not change the rep.
        if not _rep_kwarg:
            # The base __init__ will make this a UnitSphericalRepresentation
            # This makes it Wrap180 instead
            if isinstance(self._data, UnitSphericalRepresentation):
                self._data = UnitSphericalWrap180Representation(
                    lat=self._data.lat, lon=self._data.lon)
                self.representation = UnitSphericalWrap180Representation
            # Make a Spherical Wrap180 instead
            elif isinstance(self._data, SphericalRepresentation):
                self._data = SphericalWrap180Representation(
                    lat=self._data.lat,
                    lon=self._data.lon,
                    distance=self._data.distance)
                self.representation = SphericalWrap180Representation

    def calculate_distance(self):
        """
        This method calculates the third coordinate of the Helioprojective
        frame. It assumes that the coordinate point is on the disk of the Sun
        at the rsun radius.

        If a point in the frame is off limb then NaN will be returned.

        Returns
        -------
        new_frame : `~sunpy.coordinates.frames.HelioProjective`
            A new frame instance with all the attributes of the original but
            now with a third coordinate.
        """
        # Skip if we already are 3D
        if isinstance(self._data, SphericalRepresentation):
            return self

        if not isinstance(self.observer, BaseCoordinateFrame):
            raise ConvertError("Cannot calculate distance to the solar disk "
                               "for observer '{}' "
                               "without `obstime` being specified.".format(
                                   self.observer))

        rep = self.represent_as(UnitSphericalWrap180Representation)
        lat, lon = rep.lat, rep.lon
        alpha = np.arccos(np.cos(lat) * np.cos(lon)).to(lat.unit)
        c = self.observer.radius**2 - self.rsun**2
        b = -2 * self.observer.radius * np.cos(alpha)
        d = ((-1 * b) - np.sqrt(b**2 - 4 * c)) / 2

        return self.realize_frame(
            SphericalWrap180Representation(lon=lon, lat=lat, distance=d))
Exemplo n.º 16
0
class Helioprojective(SunPyBaseCoordinateFrame):
    """
    A coordinate or frame in the Helioprojective (Cartesian) system.

    This is a projective coordinate system centered around the observer.
    It is a full spherical coordinate system with position given as longitude
    theta_x and latitude theta_y.

    Parameters
    ----------
    representation: `~astropy.coordinates.BaseRepresentation` or None.
        A representation object. If specified, other parameters must
        be in keyword form.
    Tx: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        X-axis coordinate.
    Ty: `~astropy.coordinates.Angle`  or `~astropy.units.Quantity`
        Y-axis coordinate.
    distance: `~astropy.units.Quantity`
        The radial distance from the observer to the coordinate point.
    obstime: SunPy Time
        The date and time of the observation, used to convert to heliographic
        carrington coordinates.
    observer: `~sunpy.coordinates.frames.HeliographicStonyhurst`, str
        The coordinate of the observer in the solar system. If you supply a string,
        it must be a solar system body that can be parsed by
        `~sunpy.coordinates.ephemeris.get_body_heliographic_stonyhurst`.
    rsun: `~astropy.units.Quantity`
        The physical (length) radius of the Sun. Used to calculate the position
        of the limb for calculating distance from the observer to the
        coordinate.

    Examples
    --------
    >>> from astropy.coordinates import SkyCoord
    >>> import sunpy.coordinates
    >>> import astropy.units as u
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, 5*u.km, obstime="2010/01/01T00:00:00",
    ...               frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty, distance) in (arcsec, arcsec, km)
        (0., 0., 5.)>
    >>> sc = SkyCoord(0*u.deg, 0*u.deg, obstime="2010/01/01T00:00:00", frame="helioprojective")
    >>> sc
    <SkyCoord (Helioprojective: obstime=2010-01-01T00:00:00.000, rsun=695700.0 km, observer=<HeliographicStonyhurst Coordinate for 'earth'>): (Tx, Ty) in arcsec
        (0., 0.)>
    """

    default_representation = SphericalRepresentation

    frame_specific_representation_info = {
        SphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='distance',
                                  framename='distance',
                                  defaultunit=None)
        ],
        UnitSphericalRepresentation: [
            RepresentationMapping(reprname='lon',
                                  framename='Tx',
                                  defaultunit=u.arcsec),
            RepresentationMapping(reprname='lat',
                                  framename='Ty',
                                  defaultunit=u.arcsec)
        ],
    }

    obstime = TimeFrameAttributeSunPy()
    rsun = Attribute(default=_RSUN.to(u.km))
    observer = ObserverCoordinateAttribute(HeliographicStonyhurst,
                                           default="earth")

    def calculate_distance(self):
        """
        This method calculates the third coordinate of the Helioprojective
        frame. It assumes that the coordinate point is on the disk of the Sun
        at the rsun radius.

        If a point in the frame is off limb then NaN will be returned.

        Returns
        -------
        new_frame : `~sunpy.coordinates.frames.HelioProjective`
            A new frame instance with all the attributes of the original but
            now with a third coordinate.
        """
        # Skip if we already are 3D
        distance = self.spherical.distance
        if not (distance.unit is u.one and u.allclose(distance, 1 * u.one)):
            return self

        if not isinstance(self.observer, BaseCoordinateFrame):
            raise ConvertError("Cannot calculate distance to the solar disk "
                               "for observer '{}' "
                               "without `obstime` being specified.".format(
                                   self.observer))

        rep = self.represent_as(UnitSphericalRepresentation)
        lat, lon = rep.lat, rep.lon
        alpha = np.arccos(np.cos(lat) * np.cos(lon)).to(lat.unit)
        c = self.observer.radius**2 - self.rsun**2
        b = -2 * self.observer.radius * np.cos(alpha)
        # Ingore sqrt of NaNs
        with np.errstate(invalid='ignore'):
            d = ((-1 * b) - np.sqrt(b**2 - 4 * c)) / 2

        return self.realize_frame(
            SphericalRepresentation(lon=lon, lat=lat, distance=d))