def observed_to_icrs(observed_coo, icrs_frame): # if the data are UnitSphericalRepresentation, we can skip the distance calculations is_unitspherical = (isinstance(observed_coo.data, UnitSphericalRepresentation) or observed_coo.cartesian.x.unit == u.one) usrepr = observed_coo.represent_as(UnitSphericalRepresentation) lon = usrepr.lon.to_value(u.radian) lat = usrepr.lat.to_value(u.radian) if isinstance(observed_coo, AltAz): # the 'A' indicates zen/az inputs coord_type = 'A' lat = PIOVER2 - lat else: coord_type = 'H' # first set up the astrometry context for ICRS<->CIRS at the observed_coo time astrom = erfa_astrom.get().apco(observed_coo) # Topocentric CIRS cirs_ra, cirs_dec = erfa.atoiq(coord_type, lon, lat, 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=observed_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=observed_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)
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))
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)
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))
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)
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))
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 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)
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 astrom = erfa_astrom.get().apci(cirs_coo) 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)
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 quantity_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
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)
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 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)
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)
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)
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 = 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)
def get_earth(time='now', *, include_velocity=False): """ Return a `~astropy.coordinates.SkyCoord` for the location of the Earth at a specified time in the `~sunpy.coordinates.frames.HeliographicStonyhurst` frame. The longitude will be zero by definition. Parameters ---------- time : {parse_time_types} Time to use in a parse_time-compatible format Keyword Arguments ----------------- include_velocity : `bool` If True, include the Earth's velocity in the output coordinate. Defaults to False. Returns ------- out : `~astropy.coordinates.SkyCoord` Location of the Earth in the `~sunpy.coordinates.frames.HeliographicStonyhurst` frame Notes ----- The Earth's velocity in the output coordinate will invariably be negligible in the longitude direction because the `~sunpy.coordinates.frames.HeliographicStonyhurst` frame rotates in time such that the plane of zero longitude (the XZ-plane) tracks Earth. Examples -------- >>> from sunpy.coordinates.ephemeris import get_earth >>> get_earth('2001-02-03 04:05:06') <SkyCoord (HeliographicStonyhurst: obstime=2001-02-03T04:05:06.000): (lon, lat, radius) in (deg, deg, AU) (0., -6.18656962, 0.98567647)> >>> get_earth('2001-02-03 04:05:06', include_velocity=True) <SkyCoord (HeliographicStonyhurst: obstime=2001-02-03T04:05:06.000): (lon, lat, radius) in (deg, deg, AU) (0., -6.18656962, 0.98567647) (d_lon, d_lat, d_radius) in (arcsec / s, arcsec / s, km / s) (6.42643739e-11, -0.00279484, 0.24968506)> >>> get_earth('2001-02-03 04:05:06', include_velocity=True).transform_to('heliocentricinertial') <SkyCoord (HeliocentricInertial: obstime=2001-02-03T04:05:06.000): (lon, lat, distance) in (deg, deg, AU) (58.41594489, -6.18656962, 0.98567647) (d_lon, d_lat, d_distance) in (arcsec / s, arcsec / s, km / s) (0.0424104, -0.00279484, 0.2496851)> """ earth = get_body_heliographic_stonyhurst('earth', time=time, include_velocity=include_velocity) # Explicitly set the longitude to 0 earth_repr = SphericalRepresentation(0 * u.deg, earth.lat, earth.radius) # Modify the representation in the frame while preserving all differentials (e.g., velocity) earth = earth.realize_frame( earth_repr.with_differentials(earth.spherical.differentials)) return SkyCoord(earth)
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)
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)
def skyoffset_to_reference(orbitskyoffset_coord, reference_frame, **kwargs): """Convert an sky offset frame coordinate to the reference frame.""" lon, lat, distance = inverse_track_fn(orbitskyoffset_coord, **kwargs) rep = SphericalRepresentation(lon=lon, lat=lat, distance=distance) if not hasattr(orbitskyoffset_coord, "distance"): rep = rep.represent_as(UnitSphericalRepresentation) return framecls( rep, representation_type=reference_frame.representation_type)
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)
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)
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)
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 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)
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)
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)
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)
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)