Beispiel #1
0
def gcrs_to_hcrs(gcrs_coo, hcrs_frame):

    if np.any(gcrs_coo.obstime != hcrs_frame.obstime):
        # if they GCRS obstime and HCRS obstime are not the same, we first
        # have to move to a GCRS where they are.
        frameattrs = gcrs_coo.get_frame_attr_names()
        frameattrs['obstime'] = hcrs_frame.obstime
        gcrs_coo = gcrs_coo.transform_to(GCRS(**frameattrs))

    srepr = gcrs_coo.represent_as(SphericalRepresentation)
    gcrs_ra = srepr.lon.to_value(u.radian)
    gcrs_dec = srepr.lat.to_value(u.radian)

    # set up the astrometry context for ICRS<->GCRS and then convert to ICRS
    # coordinate direction
    obs_pv = erfa.pav2pv(
        gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m),
        gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m/u.s))

    jd1, jd2 = get_jd12(hcrs_frame.obstime, 'tdb')
    earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime)
    astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric)

    i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom)

    # convert to Quantity objects
    i_ra = u.Quantity(i_ra, u.radian, copy=False)
    i_dec = u.Quantity(i_dec, u.radian, copy=False)
    if gcrs_coo.data.get_name() == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just use the coordinate direction to yield the
        # infinite-distance/no parallax answer
        newrep = UnitSphericalRepresentation(lat=i_dec, lon=i_ra, copy=False)
    else:
        # When there is a distance, apply the parallax/offset to the
        # Heliocentre as the last step to ensure round-tripping with the
        # hcrs_to_gcrs transform

        # Note that the distance in intermedrep is *not* a real distance as it
        # does not include the offset back to the Heliocentre
        intermedrep = SphericalRepresentation(lat=i_dec, lon=i_ra,
                                              distance=srepr.distance,
                                              copy=False)

        # astrom['eh'] and astrom['em'] contain Sun to observer unit vector,
        # and distance, respectively. Shapes are (X) and (X,3), where (X) is the
        # shape resulting from broadcasting the shape of the times object
        # against the shape of the pv array.
        # broadcast em to eh and scale eh
        eh = astrom['eh'] * astrom['em'][..., np.newaxis]
        eh = CartesianRepresentation(eh, unit=u.au, xyz_axis=-1, copy=False)

        newrep = intermedrep.to_cartesian() + eh

    return hcrs_frame.realize_frame(newrep)
Beispiel #2
0
def altaz_to_cirs(altaz_coo, cirs_frame):
    usrepr = altaz_coo.represent_as(UnitSphericalRepresentation)
    az = usrepr.lon.to_value(u.radian)
    zen = PIOVER2 - usrepr.lat.to_value(u.radian)

    # first set up the astrometry context for ICRS<->CIRS at the altaz_coo time
    astrom = erfa_astrom.get().apio13(altaz_coo)

    # the 'A' indicates zen/az inputs
    cirs_ra, cirs_dec = erfa.atoiq('A', az, zen, astrom) * u.radian
    if isinstance(altaz_coo.data, UnitSphericalRepresentation
                  ) or altaz_coo.cartesian.x.unit == u.one:
        cirs_at_aa_time = CIRS(ra=cirs_ra,
                               dec=cirs_dec,
                               distance=None,
                               obstime=altaz_coo.obstime)
    else:
        # treat the output of atoiq as an "astrometric" RA/DEC, so to get the
        # actual RA/Dec from the observers vantage point, we have to reverse
        # the vector operation of cirs_to_altaz (see there for more detail)

        loccirs = altaz_coo.location.get_itrs(
            altaz_coo.obstime).transform_to(cirs_frame)

        astrometric_rep = SphericalRepresentation(lon=cirs_ra,
                                                  lat=cirs_dec,
                                                  distance=altaz_coo.distance)
        newrepr = astrometric_rep + loccirs.cartesian
        cirs_at_aa_time = CIRS(newrepr, obstime=altaz_coo.obstime)

    # this final transform may be a no-op if the obstimes are the same
    return cirs_at_aa_time.transform_to(cirs_frame)
Beispiel #3
0
def hcc_to_hpc(helioccoord, heliopframe):
    """
    Convert from Heliocentic Cartesian to Helioprojective Cartesian.
    """
    if not _observers_are_equal(helioccoord.observer, heliopframe.observer):
        raise ConvertError(
            "Cannot directly transform heliocentric coordinates to "
            "helioprojective coordinates for different "
            "observers {} and {}. See discussion in this GH issue: "
            "https://github.com/sunpy/sunpy/issues/2712. Try converting to "
            "an intermediate heliographic Stonyhurst frame.".format(
                helioccoord.observer, heliopframe.observer))

    x = helioccoord.x.to(u.m)
    y = helioccoord.y.to(u.m)
    z = helioccoord.z.to(u.m)

    # d is calculated as the distance between the points
    # (x,y,z) and (0,0,D0).
    distance = np.sqrt(x**2 + y**2 + (helioccoord.observer.radius - z)**2)

    hpcx = np.rad2deg(np.arctan2(x, helioccoord.observer.radius - z))
    hpcy = np.rad2deg(np.arcsin(y / distance))

    representation = SphericalRepresentation(hpcx, hpcy, distance.to(u.km))

    return heliopframe.realize_frame(representation)
Beispiel #4
0
def icrs_to_altaz(icrs_coo, altaz_frame):
    # if the data are UnitSphericalRepresentation, we can skip the distance calculations
    is_unitspherical = (isinstance(icrs_coo.data, UnitSphericalRepresentation)
                        or icrs_coo.cartesian.x.unit == u.one)
    # first set up the astrometry context for ICRS<->AltAz
    astrom = erfa_astrom.get().apco(altaz_frame)

    # correct for parallax to find BCRS direction from observer (as in erfa.pmpx)
    if is_unitspherical:
        srepr = icrs_coo.spherical
    else:
        observer_icrs = CartesianRepresentation(astrom['eb'],
                                                unit=u.au,
                                                xyz_axis=-1,
                                                copy=False)
        srepr = (icrs_coo.cartesian -
                 observer_icrs).represent_as(SphericalRepresentation)

    # convert to topocentric CIRS
    cirs_ra, cirs_dec = atciqz(srepr, astrom)

    # now perform AltAz conversion
    az, zen, ha, odec, ora = erfa.atioq(cirs_ra, cirs_dec, astrom)
    alt = PIOVER2 - zen
    if is_unitspherical:
        aa_srepr = UnitSphericalRepresentation(az << u.radian,
                                               alt << u.radian,
                                               copy=False)
    else:
        aa_srepr = SphericalRepresentation(az << u.radian,
                                           alt << u.radian,
                                           srepr.distance,
                                           copy=False)
    return altaz_frame.realize_frame(aa_srepr)
Beispiel #5
0
    def __init__(self, *args, **kwargs):
        _rep_kwarg = kwargs.get('representation', None)
        wrap = kwargs.pop('wrap_longitude', True)

        if ('radius' in kwargs and kwargs['radius'].unit is u.one
                and u.allclose(kwargs['radius'], 1 * u.one)):
            kwargs['radius'] = RSUN_METERS.to(u.km)

        super(HeliographicStonyhurst, self).__init__(*args, **kwargs)

        # Make 3D if specified as 2D
        # If representation was explicitly passed, do not change the rep.
        if not _rep_kwarg:
            # If we were passed a 3D rep extract the distance, otherwise
            # calculate it from RSUN.
            if isinstance(self._data, UnitSphericalRepresentation):
                distance = RSUN_METERS.to(u.km)
                self._data = SphericalRepresentation(lat=self._data.lat,
                                                     lon=self._data.lon,
                                                     distance=distance)

        if wrap and isinstance(
                self._data,
            (UnitSphericalRepresentation, SphericalRepresentation)):
            self._data.lon.wrap_angle = self._default_wrap_angle
Beispiel #6
0
    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))
Beispiel #7
0
    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))
Beispiel #8
0
    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 u.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))
def cirs_to_icrs(cirs_coo, icrs_frame):
    # set up the astrometry context for ICRS<->cirs and then convert to
    # astrometric coordinate direction
    astrom = erfa_astrom.get().apci(cirs_coo)
    srepr = cirs_coo.represent_as(SphericalRepresentation)
    i_ra, i_dec = aticq(srepr.without_differentials(), astrom)

    if cirs_coo.data.get_name() == 'unitspherical' or cirs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just use the coordinate direction to yield the
        # infinite-distance/no parallax answer
        newrep = UnitSphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False),
                                             lon=u.Quantity(i_ra, u.radian, copy=False),
                                             copy=False)
    else:
        # When there is a distance, apply the parallax/offset to the SSB as the
        # last step - ensures round-tripping with the icrs_to_cirs transform

        # the distance in intermedrep is *not* a real distance as it does not
        # include the offset back to the SSB
        intermedrep = SphericalRepresentation(lat=u.Quantity(i_dec, u.radian, copy=False),
                                              lon=u.Quantity(i_ra, u.radian, copy=False),
                                              distance=srepr.distance,
                                              copy=False)

        astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au,
                                            xyz_axis=-1, copy=False)
        newrep = intermedrep + astrom_eb

    return icrs_frame.realize_frame(newrep)
def cirs_to_observed(cirs_coo, observed_frame):
    if (np.any(observed_frame.location != cirs_coo.location) or
            np.any(cirs_coo.obstime != observed_frame.obstime)):
        cirs_coo = cirs_coo.transform_to(CIRS(obstime=observed_frame.obstime,
                                              location=observed_frame.location))

    # if the data are UnitSphericalRepresentation, we can skip the distance calculations
    is_unitspherical = (isinstance(cirs_coo.data, UnitSphericalRepresentation) or
                        cirs_coo.cartesian.x.unit == u.one)

    # We used to do "astrometric" corrections here, but these are no longer necesssary
    # CIRS has proper topocentric behaviour
    usrepr = cirs_coo.represent_as(UnitSphericalRepresentation)
    cirs_ra = usrepr.lon.to_value(u.radian)
    cirs_dec = usrepr.lat.to_value(u.radian)
    # first set up the astrometry context for CIRS<->observed
    astrom = erfa_astrom.get().apio(observed_frame)

    if isinstance(observed_frame, AltAz):
        lon, zen, _, _, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)
        lat = PIOVER2 - zen
    else:
        _, _, lon, lat, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)

    if is_unitspherical:
        rep = UnitSphericalRepresentation(lat=u.Quantity(lat, u.radian, copy=False),
                                          lon=u.Quantity(lon, u.radian, copy=False),
                                          copy=False)
    else:
        # since we've transformed to CIRS at the observatory location, just use CIRS distance
        rep = SphericalRepresentation(lat=u.Quantity(lat, u.radian, copy=False),
                                      lon=u.Quantity(lon, u.radian, copy=False),
                                      distance=cirs_coo.distance,
                                      copy=False)
    return observed_frame.realize_frame(rep)
def icrs_to_cirs(icrs_coo, cirs_frame):
    # first set up the astrometry context for ICRS<->CIRS
    astrom = erfa_astrom.get().apci(cirs_frame)

    if icrs_coo.data.get_name() == 'unitspherical' or icrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just do the infinite-distance/no parallax calculation
        srepr = icrs_coo.spherical
        cirs_ra, cirs_dec = atciqz(srepr.without_differentials(), astrom)

        newrep = UnitSphericalRepresentation(lat=u.Quantity(cirs_dec, u.radian, copy=False),
                                             lon=u.Quantity(cirs_ra, u.radian, copy=False),
                                             copy=False)
    else:
        # When there is a distance,  we first offset for parallax to get the
        # astrometric coordinate direction and *then* run the ERFA transform for
        # no parallax/PM. This ensures reversibility and is more sensible for
        # inside solar system objects
        astrom_eb = CartesianRepresentation(astrom['eb'], unit=u.au,
                                            xyz_axis=-1, copy=False)
        newcart = icrs_coo.cartesian - astrom_eb
        srepr = newcart.represent_as(SphericalRepresentation)
        cirs_ra, cirs_dec = atciqz(srepr.without_differentials(), astrom)

        newrep = SphericalRepresentation(lat=u.Quantity(cirs_dec, u.radian, copy=False),
                                         lon=u.Quantity(cirs_ra, u.radian, copy=False),
                                         distance=srepr.distance, copy=False)

    return cirs_frame.realize_frame(newrep)
Beispiel #12
0
def hcc_to_hgs(helioccoord, heliogframe):
    """
    Convert from Heliocentric Cartesian to Heliographic Stonyhurst.
    """
    if not isinstance(helioccoord.observer, BaseCoordinateFrame):
        raise ConvertError("Cannot transform heliocentric coordinates to "
                           "heliographic coordinates for observer '{}' "
                           "without `obstime` being specified.".format(
                               helioccoord.observer))

    x = helioccoord.x.to(u.m)
    y = helioccoord.y.to(u.m)
    z = helioccoord.z.to(u.m)

    l0_rad = helioccoord.observer.lon
    b0_deg = helioccoord.observer.lat

    cosb = np.cos(np.deg2rad(b0_deg))
    sinb = np.sin(np.deg2rad(b0_deg))

    hecr = np.sqrt(x**2 + y**2 + z**2)
    hgln = np.arctan2(x, z * cosb - y * sinb) + l0_rad
    hglt = np.arcsin((y * cosb + z * sinb) / hecr)

    representation = SphericalRepresentation(np.rad2deg(hgln),
                                             np.rad2deg(hglt), hecr.to(u.km))
    return heliogframe.realize_frame(representation)
Beispiel #13
0
def gcrs_to_hcrs(gcrs_coo, hcrs_frame):

    if np.any(gcrs_coo.obstime != hcrs_frame.obstime):
        # if they GCRS obstime and HCRS obstime are not the same, we first
        # have to move to a GCRS where they are.
        frameattrs = gcrs_coo.get_frame_attr_names()
        frameattrs['obstime'] = hcrs_frame.obstime
        gcrs_coo = gcrs_coo.transform_to(GCRS(**frameattrs))

    srepr = gcrs_coo.represent_as(SphericalRepresentation)
    gcrs_ra = srepr.lon.to_value(u.radian)
    gcrs_dec = srepr.lat.to_value(u.radian)

    # set up the astrometry context for ICRS<->GCRS and then convert to ICRS
    # coordinate direction
    astrom = erfa_astrom.get().apcs(gcrs_coo)
    i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom)

    # convert to Quantity objects
    i_ra = u.Quantity(i_ra, u.radian, copy=False)
    i_dec = u.Quantity(i_dec, u.radian, copy=False)
    if gcrs_coo.data.get_name() == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just use the coordinate direction to yield the
        # infinite-distance/no parallax answer
        newrep = UnitSphericalRepresentation(lat=i_dec, lon=i_ra, copy=False)
    else:
        # When there is a distance, apply the parallax/offset to the
        # Heliocentre as the last step to ensure round-tripping with the
        # hcrs_to_gcrs transform

        # Note that the distance in intermedrep is *not* a real distance as it
        # does not include the offset back to the Heliocentre
        intermedrep = SphericalRepresentation(lat=i_dec, lon=i_ra,
                                              distance=srepr.distance,
                                              copy=False)

        # astrom['eh'] and astrom['em'] contain Sun to observer unit vector,
        # and distance, respectively. Shapes are (X) and (X,3), where (X) is the
        # shape resulting from broadcasting the shape of the times object
        # against the shape of the pv array.
        # broadcast em to eh and scale eh
        eh = astrom['eh'] * astrom['em'][..., np.newaxis]
        eh = CartesianRepresentation(eh, unit=u.au, xyz_axis=-1, copy=False)

        newrep = intermedrep.to_cartesian() + eh

    return hcrs_frame.realize_frame(newrep)
def icrs_to_gcrs(icrs_coo, gcrs_frame):
    # first set up the astrometry context for ICRS<->GCRS. There are a few steps...
    # get the position and velocity arrays for the observatory.  Need to
    # have xyz in last dimension, and pos/vel in one-but-last.
    # (Note could use np.stack once our minimum numpy version is >=1.10.)
    obs_pv = pav2pv(
        gcrs_frame.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m),
        gcrs_frame.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m / u.s))

    # find the position and velocity of earth
    jd1, jd2 = get_jd12(gcrs_frame.obstime, 'tdb')
    earth_pv, earth_heliocentric = prepare_earth_position_vel(
        gcrs_frame.obstime)

    # get astrometry context object, astrom.
    astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric)

    if icrs_coo.data.get_name(
    ) == 'unitspherical' or icrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just do the infinite-distance/no parallax calculation
        usrepr = icrs_coo.represent_as(UnitSphericalRepresentation)
        i_ra = usrepr.lon.to_value(u.radian)
        i_dec = usrepr.lat.to_value(u.radian)
        gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom)

        newrep = UnitSphericalRepresentation(lat=u.Quantity(gcrs_dec,
                                                            u.radian,
                                                            copy=False),
                                             lon=u.Quantity(gcrs_ra,
                                                            u.radian,
                                                            copy=False),
                                             copy=False)
    else:
        # When there is a distance,  we first offset for parallax to get the
        # BCRS coordinate direction and *then* run the ERFA transform for no
        # parallax/PM. This ensures reversibility and is more sensible for
        # inside solar system objects
        astrom_eb = CartesianRepresentation(astrom['eb'],
                                            unit=u.au,
                                            xyz_axis=-1,
                                            copy=False)
        newcart = icrs_coo.cartesian - astrom_eb

        srepr = newcart.represent_as(SphericalRepresentation)
        i_ra = srepr.lon.to_value(u.radian)
        i_dec = srepr.lat.to_value(u.radian)
        gcrs_ra, gcrs_dec = atciqz(i_ra, i_dec, astrom)

        newrep = SphericalRepresentation(lat=u.Quantity(gcrs_dec,
                                                        u.radian,
                                                        copy=False),
                                         lon=u.Quantity(gcrs_ra,
                                                        u.radian,
                                                        copy=False),
                                         distance=srepr.distance,
                                         copy=False)

    return gcrs_frame.realize_frame(newrep)
Beispiel #15
0
def hgs_to_hgc(hgscoord, hgcframe):
    """
    Transform from Heliographic Stonyhurst to Heliograpic Carrington.
    """
    c_lon = hgscoord.spherical.lon + _carrington_offset(hgscoord.obstime).to(
        u.deg)
    representation = SphericalRepresentation(c_lon, hgscoord.lat,
                                             hgscoord.radius)
    hgcframe = hgcframe.__class__(obstime=hgscoord.obstime)
    return hgcframe.realize_frame(representation)
Beispiel #16
0
def cirs_to_altaz(cirs_coo, altaz_frame):
    if np.any(cirs_coo.obstime != altaz_frame.obstime):
        # the only frame attribute for the current CIRS is the obstime, but this
        # would need to be updated if a future change allowed specifying an
        # Earth location algorithm or something
        cirs_coo = cirs_coo.transform_to(CIRS(obstime=altaz_frame.obstime))

    # we use the same obstime everywhere now that we know they're the same
    obstime = cirs_coo.obstime

    # if the data are UnitSphericalRepresentation, we can skip the distance calculations
    is_unitspherical = (isinstance(cirs_coo.data, UnitSphericalRepresentation)
                        or cirs_coo.cartesian.x.unit == u.one)

    if is_unitspherical:
        usrepr = cirs_coo.represent_as(UnitSphericalRepresentation)
        cirs_ra = usrepr.lon.to_value(u.radian)
        cirs_dec = usrepr.lat.to_value(u.radian)
    else:
        # compute an "astrometric" ra/dec -i.e., the direction of the
        # displacement vector from the observer to the target in CIRS
        loccirs = altaz_frame.location.get_itrs(
            cirs_coo.obstime).transform_to(cirs_coo)
        diffrepr = (
            cirs_coo.cartesian -
            loccirs.cartesian).represent_as(UnitSphericalRepresentation)

        cirs_ra = diffrepr.lon.to_value(u.radian)
        cirs_dec = diffrepr.lat.to_value(u.radian)

    # first set up the astrometry context for CIRS<->AltAz
    astrom = erfa_astrom.get().apio13(altaz_frame)

    az, zen, _, _, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)

    if is_unitspherical:
        rep = UnitSphericalRepresentation(lat=u.Quantity(PIOVER2 - zen,
                                                         u.radian,
                                                         copy=False),
                                          lon=u.Quantity(az,
                                                         u.radian,
                                                         copy=False),
                                          copy=False)
    else:
        # now we get the distance as the cartesian distance from the earth
        # location to the coordinate location
        locitrs = altaz_frame.location.get_itrs(obstime)
        distance = locitrs.separation_3d(cirs_coo)
        rep = SphericalRepresentation(lat=u.Quantity(PIOVER2 - zen,
                                                     u.radian,
                                                     copy=False),
                                      lon=u.Quantity(az, u.radian, copy=False),
                                      distance=distance,
                                      copy=False)
    return altaz_frame.realize_frame(rep)
Beispiel #17
0
def _sun_north_angle_to_z(frame):
    """
    Return the angle between solar north and the Z axis of the provided frame's coordinate system
    and observation time.
    """
    # Find the Sun center in HGS at the frame's observation time(s)
    sun_center_repr = SphericalRepresentation(0*u.deg, 0*u.deg, 0*u.km)
    # The representation is repeated for as many times as are in obstime prior to transformation
    sun_center = SkyCoord(sun_center_repr._apply('repeat', frame.obstime.size),
                          frame=HGS, obstime=frame.obstime)

    # Find the Sun north in HGS at the frame's observation time(s)
    # Only a rough value of the solar radius is needed here because, after the cross product,
    #   only the direction from the Sun center to the Sun north pole matters
    sun_north_repr = SphericalRepresentation(0*u.deg, 90*u.deg, 690000*u.km)
    # The representation is repeated for as many times as are in obstime prior to transformation
    sun_north = SkyCoord(sun_north_repr._apply('repeat', frame.obstime.size),
                         frame=HGS, obstime=frame.obstime)

    # Find the Sun center and Sun north in the frame's coordinate system
    sky_normal = sun_center.transform_to(frame).data.to_cartesian()
    sun_north = sun_north.transform_to(frame).data.to_cartesian()

    # Use cross products to obtain the sky projections of the two vectors (rotated by 90 deg)
    sun_north_in_sky = sun_north.cross(sky_normal)
    z_in_sky = CartesianRepresentation(0, 0, 1).cross(sky_normal)

    # Normalize directional vectors
    sky_normal /= sky_normal.norm()
    sun_north_in_sky /= sun_north_in_sky.norm()
    z_in_sky /= z_in_sky.norm()

    # Calculate the signed angle between the two projected vectors
    cos_theta = sun_north_in_sky.dot(z_in_sky)
    sin_theta = sun_north_in_sky.cross(z_in_sky).dot(sky_normal)
    angle = np.arctan2(sin_theta, cos_theta).to('deg')

    # If there is only one time, this function's output should be scalar rather than array
    if angle.size == 1:
        angle = angle[0]

    return Angle(angle)
Beispiel #18
0
def altaz_to_icrs(altaz_coo, icrs_frame):
    # if the data are UnitSphericalRepresentation, we can skip the distance calculations
    is_unitspherical = (isinstance(altaz_coo.data, UnitSphericalRepresentation)
                        or altaz_coo.cartesian.x.unit == u.one)

    usrepr = altaz_coo.represent_as(UnitSphericalRepresentation)
    az = usrepr.lon.to_value(u.radian)
    zen = PIOVER2 - usrepr.lat.to_value(u.radian)

    # first set up the astrometry context for ICRS<->CIRS at the altaz_coo time
    astrom = erfa_astrom.get().apco(altaz_coo)

    # Topocentric CIRS
    cirs_ra, cirs_dec = erfa.atoiq('A', az, zen, astrom) << u.radian
    if is_unitspherical:
        srepr = SphericalRepresentation(cirs_ra, cirs_dec, 1, copy=False)
    else:
        srepr = SphericalRepresentation(lon=cirs_ra,
                                        lat=cirs_dec,
                                        distance=altaz_coo.distance,
                                        copy=False)

    # BCRS (Astrometric) direction to source
    bcrs_ra, bcrs_dec = aticq(srepr, astrom) << u.radian

    # Correct for parallax to get ICRS representation
    if is_unitspherical:
        icrs_srepr = UnitSphericalRepresentation(bcrs_ra, bcrs_dec, copy=False)
    else:
        icrs_srepr = SphericalRepresentation(lon=bcrs_ra,
                                             lat=bcrs_dec,
                                             distance=altaz_coo.distance,
                                             copy=False)
        observer_icrs = CartesianRepresentation(astrom['eb'],
                                                unit=u.au,
                                                xyz_axis=-1,
                                                copy=False)
        newrepr = icrs_srepr.to_cartesian() + observer_icrs
        icrs_srepr = newrepr.represent_as(SphericalRepresentation)

    return icrs_frame.realize_frame(icrs_srepr)
Beispiel #19
0
    def _apply_diffrot(self, duration, rotation_model):
        oldrepr = self.spherical

        from sunpy.physics.differential_rotation import diff_rot
        log.debug(f"Applying {duration} of solar rotation")
        newlon = oldrepr.lon + diff_rot(duration,
                                        oldrepr.lat,
                                        rot_type=rotation_model,
                                        frame_time='sidereal')
        newrepr = SphericalRepresentation(newlon, oldrepr.lat, oldrepr.distance)

        return self.realize_frame(newrepr)
Beispiel #20
0
def hgc_to_hgs(hgccoord, hgsframe):
    """
    Convert from Heliograpic Carrington to Heliographic Stonyhurst.
    """
    if hgccoord.obstime:
        obstime = hgccoord.obstime
    else:
        obstime = hgsframe.obstime
    s_lon = hgccoord.spherical.lon - _carrington_offset(obstime).to(u.deg)
    representation = SphericalRepresentation(s_lon, hgccoord.lat,
                                             hgccoord.radius)
    return hgsframe.realize_frame(representation)
def gcrs_to_icrs(gcrs_coo, icrs_frame):
    srepr = gcrs_coo.represent_as(SphericalRepresentation)
    gcrs_ra = srepr.lon.to_value(u.radian)
    gcrs_dec = srepr.lat.to_value(u.radian)

    # set up the astrometry context for ICRS<->GCRS and then convert to BCRS
    # coordinate direction
    obs_pv = pav2pv(
        gcrs_coo.obsgeoloc.get_xyz(xyz_axis=-1).to_value(u.m),
        gcrs_coo.obsgeovel.get_xyz(xyz_axis=-1).to_value(u.m / u.s))

    jd1, jd2 = get_jd12(gcrs_coo.obstime, 'tdb')

    earth_pv, earth_heliocentric = prepare_earth_position_vel(gcrs_coo.obstime)
    astrom = erfa.apcs(jd1, jd2, obs_pv, earth_pv, earth_heliocentric)

    i_ra, i_dec = aticq(gcrs_ra, gcrs_dec, astrom)

    if gcrs_coo.data.get_name(
    ) == 'unitspherical' or gcrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just use the coordinate direction to yield the
        # infinite-distance/no parallax answer
        newrep = UnitSphericalRepresentation(lat=u.Quantity(i_dec,
                                                            u.radian,
                                                            copy=False),
                                             lon=u.Quantity(i_ra,
                                                            u.radian,
                                                            copy=False),
                                             copy=False)
    else:
        # When there is a distance, apply the parallax/offset to the SSB as the
        # last step - ensures round-tripping with the icrs_to_gcrs transform

        # the distance in intermedrep is *not* a real distance as it does not
        # include the offset back to the SSB
        intermedrep = SphericalRepresentation(lat=u.Quantity(i_dec,
                                                             u.radian,
                                                             copy=False),
                                              lon=u.Quantity(i_ra,
                                                             u.radian,
                                                             copy=False),
                                              distance=srepr.distance,
                                              copy=False)

        astrom_eb = CartesianRepresentation(astrom['eb'],
                                            unit=u.au,
                                            xyz_axis=-1,
                                            copy=False)
        newrep = intermedrep + astrom_eb

    return icrs_frame.realize_frame(newrep)
Beispiel #22
0
def hgs_to_hgc(hgscoord, hgcframe):
    """
    Transform from Heliographic Stonyhurst to Heliograpic Carrington.
    """
    if hgcframe.obstime is None or np.any(hgcframe.obstime != hgscoord.obstime):
        raise ValueError("Can not transform from Heliographic Stonyhurst to "
                         "Heliographic Carrington, unless both frames have matching obstime.")

    c_lon = hgscoord.spherical.lon + _carrington_offset(hgscoord.obstime).to(u.deg)
    representation = SphericalRepresentation(c_lon, hgscoord.spherical.lat,
                                             hgscoord.spherical.distance)
    hgcframe = hgcframe.__class__(obstime=hgscoord.obstime)

    return hgcframe.realize_frame(representation)
Beispiel #23
0
def hgc_to_hgs(hgccoord, hgsframe):
    """
    Convert from Heliograpic Carrington to Heliographic Stonyhurst.
    """
    if hgsframe.obstime is None or np.any(hgsframe.obstime != hgccoord.obstime):
        raise ValueError("Can not transform from Heliographic Carrington to "
                         "Heliographic Stonyhurst, unless both frames have matching obstime.")
    obstime = hgsframe.obstime
    s_lon = hgccoord.spherical.lon - _carrington_offset(obstime).to(
        u.deg)
    representation = SphericalRepresentation(s_lon, hgccoord.spherical.lat,
                                             hgccoord.spherical.distance)

    return hgsframe.realize_frame(representation)
def icrs_to_cirs(icrs_coo, cirs_frame):
    # first set up the astrometry context for ICRS<->CIRS
    jd1, jd2 = get_jd12(cirs_frame.obstime, 'tt')
    x, y, s = get_cip(jd1, jd2)
    earth_pv, earth_heliocentric = prepare_earth_position_vel(
        cirs_frame.obstime)
    # erfa.apci requests TDB but TT can be used instead of TDB without any significant impact on accuracy
    astrom = erfa.apci(jd1, jd2, earth_pv, earth_heliocentric, x, y, s)

    if icrs_coo.data.get_name(
    ) == 'unitspherical' or icrs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just do the infinite-distance/no parallax calculation
        usrepr = icrs_coo.represent_as(UnitSphericalRepresentation)
        i_ra = usrepr.lon.to_value(u.radian)
        i_dec = usrepr.lat.to_value(u.radian)
        cirs_ra, cirs_dec = atciqz(i_ra, i_dec, astrom)

        newrep = UnitSphericalRepresentation(lat=u.Quantity(cirs_dec,
                                                            u.radian,
                                                            copy=False),
                                             lon=u.Quantity(cirs_ra,
                                                            u.radian,
                                                            copy=False),
                                             copy=False)
    else:
        # When there is a distance,  we first offset for parallax to get the
        # astrometric coordinate direction and *then* run the ERFA transform for
        # no parallax/PM. This ensures reversibility and is more sensible for
        # inside solar system objects
        astrom_eb = CartesianRepresentation(astrom['eb'],
                                            unit=u.au,
                                            xyz_axis=-1,
                                            copy=False)
        newcart = icrs_coo.cartesian - astrom_eb

        srepr = newcart.represent_as(SphericalRepresentation)
        i_ra = srepr.lon.to_value(u.radian)
        i_dec = srepr.lat.to_value(u.radian)
        cirs_ra, cirs_dec = atciqz(i_ra, i_dec, astrom)

        newrep = SphericalRepresentation(lat=u.Quantity(cirs_dec,
                                                        u.radian,
                                                        copy=False),
                                         lon=u.Quantity(cirs_ra,
                                                        u.radian,
                                                        copy=False),
                                         distance=srepr.distance,
                                         copy=False)

    return cirs_frame.realize_frame(newrep)
Beispiel #25
0
def altaz_to_cirs(altaz_coo, cirs_frame):
    usrepr = altaz_coo.represent_as(UnitSphericalRepresentation)
    az = usrepr.lon.to_value(u.radian)
    zen = PIOVER2 - usrepr.lat.to_value(u.radian)

    lon, lat, height = altaz_coo.location.to_geodetic('WGS84')
    xp, yp = get_polar_motion(altaz_coo.obstime)

    # first set up the astrometry context for ICRS<->CIRS at the altaz_coo time
    jd1, jd2 = get_jd12(altaz_coo.obstime, 'utc')
    astrom = erfa.apio13(
        jd1,
        jd2,
        get_dut1utc(altaz_coo.obstime),
        lon.to_value(u.radian),
        lat.to_value(u.radian),
        height.to_value(u.m),
        xp,
        yp,  # polar motion
        # all below are already in correct units because they are QuantityFrameAttribues
        altaz_coo.pressure.value,
        altaz_coo.temperature.value,
        altaz_coo.relative_humidity.value,
        altaz_coo.obswl.value)

    # the 'A' indicates zen/az inputs
    cirs_ra, cirs_dec = erfa.atoiq('A', az, zen, astrom) * u.radian
    if isinstance(altaz_coo.data, UnitSphericalRepresentation
                  ) or altaz_coo.cartesian.x.unit == u.one:
        cirs_at_aa_time = CIRS(ra=cirs_ra,
                               dec=cirs_dec,
                               distance=None,
                               obstime=altaz_coo.obstime)
    else:
        # treat the output of atoiq as an "astrometric" RA/DEC, so to get the
        # actual RA/Dec from the observers vantage point, we have to reverse
        # the vector operation of cirs_to_altaz (see there for more detail)

        loccirs = altaz_coo.location.get_itrs(
            altaz_coo.obstime).transform_to(cirs_frame)

        astrometric_rep = SphericalRepresentation(lon=cirs_ra,
                                                  lat=cirs_dec,
                                                  distance=altaz_coo.distance)
        newrepr = astrometric_rep + loccirs.cartesian
        cirs_at_aa_time = CIRS(newrepr, obstime=altaz_coo.obstime)

    # this final transform may be a no-op if the obstimes are the same
    return cirs_at_aa_time.transform_to(cirs_frame)
Beispiel #26
0
    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
        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))
def cirs_to_icrs(cirs_coo, icrs_frame):
    srepr = cirs_coo.represent_as(SphericalRepresentation)
    cirs_ra = srepr.lon.to_value(u.radian)
    cirs_dec = srepr.lat.to_value(u.radian)

    # set up the astrometry context for ICRS<->cirs and then convert to
    # astrometric coordinate direction
    jd1, jd2 = get_jd12(cirs_coo.obstime, 'tt')
    x, y, s = get_cip(jd1, jd2)
    earth_pv, earth_heliocentric = prepare_earth_position_vel(cirs_coo.obstime)
    # erfa.apci requests TDB but TT can be used instead of TDB without any significant impact on accuracy
    astrom = erfa.apci(jd1, jd2, earth_pv, earth_heliocentric, x, y, s)
    i_ra, i_dec = aticq(cirs_ra, cirs_dec, astrom)

    if cirs_coo.data.get_name(
    ) == 'unitspherical' or cirs_coo.data.to_cartesian().x.unit == u.one:
        # if no distance, just use the coordinate direction to yield the
        # infinite-distance/no parallax answer
        newrep = UnitSphericalRepresentation(lat=u.Quantity(i_dec,
                                                            u.radian,
                                                            copy=False),
                                             lon=u.Quantity(i_ra,
                                                            u.radian,
                                                            copy=False),
                                             copy=False)
    else:
        # When there is a distance, apply the parallax/offset to the SSB as the
        # last step - ensures round-tripping with the icrs_to_cirs transform

        # the distance in intermedrep is *not* a real distance as it does not
        # include the offset back to the SSB
        intermedrep = SphericalRepresentation(lat=u.Quantity(i_dec,
                                                             u.radian,
                                                             copy=False),
                                              lon=u.Quantity(i_ra,
                                                             u.radian,
                                                             copy=False),
                                              distance=srepr.distance,
                                              copy=False)

        astrom_eb = CartesianRepresentation(astrom['eb'],
                                            unit=u.au,
                                            xyz_axis=-1,
                                            copy=False)
        newrep = intermedrep + astrom_eb

    return icrs_frame.realize_frame(newrep)
Beispiel #28
0
def hcc_to_hpc(helioccoord, heliopframe):
    """
    Convert from Heliocentic Cartesian to Helioprojective Cartesian.
    """

    x = helioccoord.x.to(u.m)
    y = helioccoord.y.to(u.m)
    z = helioccoord.z.to(u.m)

    # d is calculated as the distance between the points
    # (x,y,z) and (0,0,D0).
    distance = np.sqrt(x**2 + y**2 + (helioccoord.observer.radius - z)**2)

    hpcx = np.rad2deg(np.arctan2(x, helioccoord.observer.radius - z))
    hpcy = np.rad2deg(np.arcsin(y / distance))

    representation = SphericalRepresentation(hpcx, hpcy, distance.to(u.km))

    return heliopframe.realize_frame(representation)
Beispiel #29
0
    def __init__(self, *args, **kwargs):
        _rep_kwarg = kwargs.get('representation_type', None)

        if ('radius' in kwargs and kwargs['radius'].unit is u.one
                and u.allclose(kwargs['radius'], 1 * u.one)):
            kwargs['radius'] = _RSUN.to(u.km)

        super().__init__(*args, **kwargs)

        # Make 3D if specified as 2D
        # If representation was explicitly passed, do not change the rep.
        if not _rep_kwarg:
            # If we were passed a 3D rep extract the distance, otherwise
            # calculate it from _RSUN.
            if isinstance(self._data, UnitSphericalRepresentation):
                distance = _RSUN.to(u.km)
                self._data = SphericalRepresentation(lat=self._data.lat,
                                                     lon=self._data.lon,
                                                     distance=distance)
Beispiel #30
0
def _sun_north_angle_to_z(frame):
    """
    Return the angle between solar north and the Z axis of the provided frame's coordinate system
    and observation time.
    """
    # Find the Sun center in HGS at the frame's observation time(s)
    sun_center_repr = SphericalRepresentation(0 * u.deg, 0 * u.deg, 0 * u.km)
    # The representation is repeated for as many times as are in obstime prior to transformation
    sun_center = SkyCoord(sun_center_repr._apply('repeat', frame.obstime.size),
                          frame=HGS,
                          obstime=frame.obstime)

    # Find the Sun north in HGS at the frame's observation time(s)
    # Only a rough value of the solar radius is needed here because, after the cross product,
    #   only the direction from the Sun center to the Sun north pole matters
    sun_north_repr = SphericalRepresentation(0 * u.deg, 90 * u.deg,
                                             690000 * u.km)
    # The representation is repeated for as many times as are in obstime prior to transformation
    sun_north = SkyCoord(sun_north_repr._apply('repeat', frame.obstime.size),
                         frame=HGS,
                         obstime=frame.obstime)

    # Find the Sun center and Sun north in the frame's coordinate system
    sky_normal = sun_center.transform_to(frame).data.to_cartesian()
    sun_north = sun_north.transform_to(frame).data.to_cartesian()

    # Use cross products to obtain the sky projections of the two vectors (rotated by 90 deg)
    sun_north_in_sky = sun_north.cross(sky_normal)
    z_in_sky = CartesianRepresentation(0, 0, 1).cross(sky_normal)

    # Normalize directional vectors
    sky_normal /= sky_normal.norm()
    sun_north_in_sky /= sun_north_in_sky.norm()
    z_in_sky /= z_in_sky.norm()

    # Calculate the signed angle between the two projected vectors
    cos_theta = sun_north_in_sky.dot(z_in_sky)
    sin_theta = sun_north_in_sky.cross(z_in_sky).dot(sky_normal)
    angle = np.arctan2(sin_theta, cos_theta).to('deg')

    # If there is only one time, this function's output should be scalar rather than array
    if angle.size == 1:
        angle = angle[0]

    return Angle(angle)
Beispiel #31
0
def uniform_spherical_random_volume(size=1, max_radius=1):
    """Generate a random sampling of points that follow a uniform volume
    density distribution within a sphere.

    Parameters
    ----------
    size : int
        The number of points to generate.
    max_radius : number, quantity-like, optional
        A dimensionless or unit-ful factor to scale the random distances.
    rng : `numpy.random.Generator`, optional
        A random number generator instance.

    Returns
    -------
    rep : `~astropy.coordinates.SphericalRepresentation`
        The random points.
    """
    rng = np.random  # can maybe switch to this being an input later - see #11628

    usph = uniform_spherical_random_surface(size=size)

    r = np.cbrt(rng.uniform(size=size)) * u.Quantity(max_radius, copy=False)
    return SphericalRepresentation(usph.lon, usph.lat, r)
Beispiel #32
0
def cirs_to_altaz(cirs_coo, altaz_frame):
    if np.any(cirs_coo.obstime != altaz_frame.obstime):
        # the only frame attribute for the current CIRS is the obstime, but this
        # would need to be updated if a future change allowed specifying an
        # Earth location algorithm or something
        cirs_coo = cirs_coo.transform_to(CIRS(obstime=altaz_frame.obstime))

    # we use the same obstime everywhere now that we know they're the same
    obstime = cirs_coo.obstime

    # if the data are UnitSphericalRepresentation, we can skip the distance calculations
    is_unitspherical = (isinstance(cirs_coo.data, UnitSphericalRepresentation)
                        or cirs_coo.cartesian.x.unit == u.one)

    if is_unitspherical:
        usrepr = cirs_coo.represent_as(UnitSphericalRepresentation)
        cirs_ra = usrepr.lon.to_value(u.radian)
        cirs_dec = usrepr.lat.to_value(u.radian)
    else:
        # compute an "astrometric" ra/dec -i.e., the direction of the
        # displacement vector from the observer to the target in CIRS
        loccirs = altaz_frame.location.get_itrs(
            cirs_coo.obstime).transform_to(cirs_coo)
        diffrepr = (
            cirs_coo.cartesian -
            loccirs.cartesian).represent_as(UnitSphericalRepresentation)

        cirs_ra = diffrepr.lon.to_value(u.radian)
        cirs_dec = diffrepr.lat.to_value(u.radian)

    lon, lat, height = altaz_frame.location.to_geodetic('WGS84')
    xp, yp = get_polar_motion(obstime)

    # first set up the astrometry context for CIRS<->AltAz
    jd1, jd2 = get_jd12(obstime, 'utc')
    astrom = erfa.apio13(
        jd1,
        jd2,
        get_dut1utc(obstime),
        lon.to_value(u.radian),
        lat.to_value(u.radian),
        height.to_value(u.m),
        xp,
        yp,  # polar motion
        # all below are already in correct units because they are QuantityFrameAttribues
        altaz_frame.pressure.value,
        altaz_frame.temperature.value,
        altaz_frame.relative_humidity.value,
        altaz_frame.obswl.value)

    az, zen, _, _, _ = erfa.atioq(cirs_ra, cirs_dec, astrom)

    if is_unitspherical:
        rep = UnitSphericalRepresentation(lat=u.Quantity(PIOVER2 - zen,
                                                         u.radian,
                                                         copy=False),
                                          lon=u.Quantity(az,
                                                         u.radian,
                                                         copy=False),
                                          copy=False)
    else:
        # now we get the distance as the cartesian distance from the earth
        # location to the coordinate location
        locitrs = altaz_frame.location.get_itrs(obstime)
        distance = locitrs.separation_3d(cirs_coo)
        rep = SphericalRepresentation(lat=u.Quantity(PIOVER2 - zen,
                                                     u.radian,
                                                     copy=False),
                                      lon=u.Quantity(az, u.radian, copy=False),
                                      distance=distance,
                                      copy=False)
    return altaz_frame.realize_frame(rep)
Beispiel #33
0
def test_representations_api():
    from astropy.coordinates.representation import SphericalRepresentation, \
        UnitSphericalRepresentation, PhysicsSphericalRepresentation, \
        CartesianRepresentation
    from astropy.coordinates import Angle, Longitude, Latitude, Distance

    # <-----------------Classes for representation of coordinate data-------------->
    # These classes inherit from a common base class and internally contain Quantity
    # objects, which are arrays (although they may act as scalars, like numpy's
    # length-0  "arrays")

    # They can be initialized with a variety of ways that make intuitive sense.
    # Distance is optional.
    UnitSphericalRepresentation(lon=8*u.hour, lat=5*u.deg)
    UnitSphericalRepresentation(lon=8*u.hourangle, lat=5*u.deg)
    SphericalRepresentation(lon=8*u.hourangle, lat=5*u.deg, distance=10*u.kpc)

    # In the initial implementation, the lat/lon/distance arguments to the
    # initializer must be in order. A *possible* future change will be to allow
    # smarter guessing of the order.  E.g. `Latitude` and `Longitude` objects can be
    # given in any order.
    UnitSphericalRepresentation(Longitude(8, u.hour), Latitude(5, u.deg))
    SphericalRepresentation(Longitude(8, u.hour), Latitude(5, u.deg), Distance(10, u.kpc))

    # Arrays of any of the inputs are fine
    UnitSphericalRepresentation(lon=[8, 9]*u.hourangle, lat=[5, 6]*u.deg)

    # Default is to copy arrays, but optionally, it can be a reference
    UnitSphericalRepresentation(lon=[8, 9]*u.hourangle, lat=[5, 6]*u.deg, copy=False)

    # strings are parsed by `Latitude` and `Longitude` constructors, so no need to
    # implement parsing in the Representation classes
    UnitSphericalRepresentation(lon=Angle('2h6m3.3s'), lat=Angle('0.1rad'))

    # Or, you can give `Quantity`s with keywords, and they will be internally
    # converted to Angle/Distance
    c1 = SphericalRepresentation(lon=8*u.hourangle, lat=5*u.deg, distance=10*u.kpc)

    # Can also give another representation object with the `reprobj` keyword.
    c2 = SphericalRepresentation.from_representation(c1)

    #  distance, lat, and lon typically will just match in shape
    SphericalRepresentation(lon=[8, 9]*u.hourangle, lat=[5, 6]*u.deg, distance=[10, 11]*u.kpc)
    # if the inputs are not the same, if possible they will be broadcast following
    # numpy's standard broadcasting rules.
    c2 = SphericalRepresentation(lon=[8, 9]*u.hourangle, lat=[5, 6]*u.deg, distance=10*u.kpc)
    assert len(c2.distance) == 2
    # when they can't be broadcast, it is a ValueError (same as Numpy)
    with raises(ValueError):
        c2 = UnitSphericalRepresentation(lon=[8, 9, 10]*u.hourangle, lat=[5, 6]*u.deg)

    # It's also possible to pass in scalar quantity lists with mixed units. These
    # are converted to array quantities following the same rule as `Quantity`: all
    # elements are converted to match the first element's units.
    c2 = UnitSphericalRepresentation(lon=Angle([8*u.hourangle, 135*u.deg]),
                                     lat=Angle([5*u.deg, (6*np.pi/180)*u.rad]))
    assert c2.lat.unit == u.deg and c2.lon.unit == u.hourangle
    npt.assert_almost_equal(c2.lon[1].value, 9)

    # The Quantity initializer itself can also be used to force the unit even if the
    # first element doesn't have the right unit
    lon = u.Quantity([120*u.deg, 135*u.deg], u.hourangle)
    lat = u.Quantity([(5*np.pi/180)*u.rad, 0.4*u.hourangle], u.deg)
    c2 = UnitSphericalRepresentation(lon, lat)

    # regardless of how input, the `lat` and `lon` come out as angle/distance
    assert isinstance(c1.lat, Angle)
    assert isinstance(c1.lat, Latitude)  # `Latitude` is an `Angle` subclass
    assert isinstance(c1.distance, Distance)

    # but they are read-only, as representations are immutable once created
    with raises(AttributeError):
        c1.lat = Latitude(5, u.deg)
    # Note that it is still possible to modify the array in-place, but this is not
    # sanctioned by the API, as this would prevent things like caching.
    c2.lat[:] = [0] * u.deg  # possible, but NOT SUPPORTED

    # To address the fact that there are various other conventions for how spherical
    # coordinates are defined, other conventions can be included as new classes.
    # Later there may be other conventions that we implement - for now just the
    # physics convention, as it is one of the most common cases.
    c3 = PhysicsSphericalRepresentation(phi=120*u.deg, theta=85*u.deg, r=3*u.kpc)

    # first dimension must be length-3 if a lone `Quantity` is passed in.
    c1 = CartesianRepresentation(np.random.randn(3, 100) * u.kpc)
    assert c1.xyz.shape[0] == 3
    assert c1.xyz.unit == u.kpc
    assert c1.x.shape[0] == 100
    assert c1.y.shape[0] == 100
    assert c1.z.shape[0] == 100
    # can also give each as separate keywords
    CartesianRepresentation(x=np.random.randn(100)*u.kpc,
                            y=np.random.randn(100)*u.kpc,
                            z=np.random.randn(100)*u.kpc)
    # if the units don't match but are all distances, they will automatically be
    # converted to match `x`
    xarr, yarr, zarr = np.random.randn(3, 100)
    c1 = CartesianRepresentation(x=xarr*u.kpc, y=yarr*u.kpc, z=zarr*u.kpc)
    c2 = CartesianRepresentation(x=xarr*u.kpc, y=yarr*u.kpc, z=zarr*u.pc)
    assert c1.xyz.unit == c2.xyz.unit == u.kpc
    assert_allclose((c1.z / 1000) - c2.z, 0*u.kpc, atol=1e-10*u.kpc)

    # representations convert into other representations via  `represent_as`
    srep = SphericalRepresentation(lon=90*u.deg, lat=0*u.deg, distance=1*u.pc)
    crep = srep.represent_as(CartesianRepresentation)
    assert_allclose(crep.x, 0*u.pc, atol=1e-10*u.pc)
    assert_allclose(crep.y, 1*u.pc, atol=1e-10*u.pc)
    assert_allclose(crep.z, 0*u.pc, atol=1e-10*u.pc)