def annual_parallax(self, time_to_treat): """Compute the position shift due to the Earth movement. Please have a look on : "Resolution of the MACHO-LMC-5 Puzzle: The Jerk-Parallax Microlens Degeneracy" Gould, Andrew 2004. http://adsabs.harvard.edu/abs/2004ApJ...606..319G :param time_to_treat: a numpy array containing the time where you want to compute this effect. :return: the shift induce by the Earth motion around the Sun :rtype: array_like **WARNING** : this is a geocentric point of view. slalib use MJD time definition, which is MJD = JD-2400000.5 """ with solar_system_ephemeris.set('builtin'): time_jd_reference = Time(self.to_par, format='jd') Earth_position_time_reference = get_body_barycentric_posvel('Earth', time_jd_reference) Sun_position_time_reference = -Earth_position_time_reference[0] Sun_speed_time_reference = -Earth_position_time_reference[1] time_jd = Time(time_to_treat, format='jd') Earth_position = get_body_barycentric_posvel('Earth', time_jd) Sun_position = -Earth_position[0] delta_Sun = Sun_position.xyz.value.T - np.c_[ time_to_treat - self.to_par] * Sun_speed_time_reference.xyz.value \ - Sun_position_time_reference.xyz.value delta_Sun_projected = np.array( [np.dot(delta_Sun, self.North), np.dot(delta_Sun, self.East)]) return delta_Sun_projected
def _targetting(departure_body, target_body, t_launch, t_arrival): """This function returns the increment in departure and arrival velocities. """ # Compute departure and arrival positions rr_dpt_body, vv_dpt_body = coord.get_body_barycentric_posvel( departure_body.name, t_launch) rr_arr_body, vv_arr_body = coord.get_body_barycentric_posvel( target_body.name, t_arrival) # Compute time of flight tof = t_arrival - t_launch if tof <= 0: return None, None, None try: (v_dpt, v_arr), = lambert(Sun.k, rr_dpt_body.xyz, rr_arr_body.xyz, tof) # Compute all the output variables dv_dpt = norm(v_dpt - vv_dpt_body.xyz) dv_arr = norm(v_arr - vv_arr_body.xyz) c3_launch = dv_dpt**2 c3_arrival = dv_arr**2 return ( c3_launch.to(u.km**2 / u.s**2).value, c3_arrival.to(u.km**2 / u.s**2).value, tof.jd, ) except AssertionError: return None, None, None
def hcrs_to_hgs(hcrscoord, hgsframe): """ Convert from HCRS to Heliographic Stonyhurst (HGS). HGS shares the same origin (the Sun) as HCRS, but has its Z axis aligned with the Sun's rotation axis and its X axis aligned with the projection of the Sun-Earth vector onto the Sun's equatorial plane (i.e., the component of the Sun-Earth vector perpendicular to the Z axis). Thus, the transformation matrix is the product of the matrix to align the Z axis (by de-tilting the Sun's rotation axis) and the matrix to align the X axis. The first matrix is independent of time and is pre-computed, while the second matrix depends on the time-varying Sun-Earth vector. """ if hgsframe.obstime is None: raise ValueError("To perform this transformation the coordinate" " Frame needs an obstime Attribute") # Check whether differentials are involved on either end has_differentials = ( (hcrscoord._data is not None and hcrscoord.data.differentials) or (hgsframe._data is not None and hgsframe.data.differentials)) # Determine the Sun-Earth vector in ICRS # Since HCRS is ICRS with an origin shift, this is also the Sun-Earth vector in HCRS # If differentials exist, also obtain Sun and Earth velocities if has_differentials: sun_pos_icrs, sun_vel = get_body_barycentric_posvel( 'sun', hgsframe.obstime) earth_pos_icrs, earth_vel = get_body_barycentric_posvel( 'earth', hgsframe.obstime) else: sun_pos_icrs = get_body_barycentric('sun', hgsframe.obstime) earth_pos_icrs = get_body_barycentric('earth', hgsframe.obstime) sun_earth = earth_pos_icrs - sun_pos_icrs # De-tilt the Sun-Earth vector to the frame with the Sun's rotation axis parallel to the Z axis sun_earth_detilt = sun_earth.transform(_SUN_DETILT_MATRIX) # Rotate the Sun-Earth vector about the Z axis so that it lies in the XZ plane rot_matrix = _rotation_matrix_reprs_to_xz_about_z(sun_earth_detilt) total_matrix = rot_matrix @ _SUN_DETILT_MATRIX # All of the above is calculated for the HGS observation time # If the HCRS observation time is different, calculate the translation in origin if not _ignore_sun_motion and np.any( hcrscoord.obstime != hgsframe.obstime): sun_pos_old_icrs = get_body_barycentric('sun', hcrscoord.obstime) offset_icrf = sun_pos_icrs - sun_pos_old_icrs else: offset_icrf = sun_pos_icrs * 0 # preserves obstime shape # Add velocity if needed (at the HGS observation time) if has_differentials: vel_icrf = (sun_vel - earth_vel).represent_as(CartesianDifferential) offset_icrf = offset_icrf.with_differentials(vel_icrf) offset = offset_icrf.transform(total_matrix) return total_matrix, offset
def _get_state(body, time): """ Computes the position of a body for a given time. """ solar_system_bodies = [ Sun, Mercury, Venus, Earth, Moon, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, ] # We check if body belongs to poliastro.bodies if body in solar_system_bodies: rr, vv = coord.get_body_barycentric_posvel(body.name, time) else: rr, vv = body.propagate(time).rv() rr = coord.CartesianRepresentation(rr) vv = coord.CartesianRepresentation(vv) return rr, vv
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ if not epoch: epoch = time.Time.now().tdb elif epoch.scale != 'tdb': epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead.".format( epoch.tdb.value), TimeScaleWarning) r, v = get_body_barycentric_posvel(body.name, epoch) if body == Moon: moon_icrs = ICRS(x=r.x, y=r.y, z=r.z, v_x=v.x, v_y=v.y, v_z=v.z, representation=CartesianRepresentation, differential_type=CartesianDifferential) moon_gcrs = moon_icrs.transform_to(GCRS(obstime=epoch)) moon_gcrs.representation = CartesianRepresentation r = CartesianRepresentation( [moon_gcrs.x, moon_gcrs.y, moon_gcrs.z]) v = CartesianRepresentation( [moon_gcrs.v_x, moon_gcrs.v_y, moon_gcrs.v_z]) return cls.from_vectors(body.parent, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch)
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ # TODO: https://github.com/poliastro/poliastro/issues/445 if not epoch: epoch = time.Time.now().tdb elif epoch.scale != 'tdb': epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead.".format( epoch.tdb.value), TimeScaleWarning) r, v = get_body_barycentric_posvel(body.name, epoch) if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials( v.represent_as(CartesianDifferential)) gcrs_cart = ICRS(icrs_cart).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials['s'].d_xyz.to(u.km / u.day), epoch) else: # TODO: The attractor is not really the Sun, but the Solar System Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def test_velocity_hcrs_hgs(): # Obtain the position/velocity of Earth in ICRS obstime = Time(['2019-01-01', '2019-04-01', '2019-07-01', '2019-10-01']) pos, vel = get_body_barycentric_posvel('earth', obstime) loc = pos.with_differentials(vel.represent_as(CartesianDifferential)) earth = SkyCoord(loc, frame='icrs', obstime=obstime) # The velocity of Earth in HGS should be very close to zero. The velocity in the HGS Y # direction is slightly further away from zero because there is true latitudinal motion. new = earth.heliographic_stonyhurst assert_quantity_allclose(new.velocity.d_x, 0 * u.km / u.s, atol=1e-15 * u.km / u.s) assert_quantity_allclose(new.velocity.d_y, 0 * u.km / u.s, atol=1e-14 * u.km / u.s) assert_quantity_allclose(new.velocity.d_x, 0 * u.km / u.s, atol=1e-15 * u.km / u.s) # Test the loopback to ICRS newer = new.icrs assert_quantity_allclose(newer.velocity.d_x, vel.x) assert_quantity_allclose(newer.velocity.d_y, vel.y) assert_quantity_allclose(newer.velocity.d_z, vel.z)
def objPosVel_wrt_SSB(objname, t, ephem, path=None, link=None): """This function computes a solar system object position and velocity respect to solar system barycenter using astropy coordinates get_body_barycentric() method. The coordinate frame is that of the underlying solar system ephemeris, which has been the ICRF (J2000) since the DE4XX series. Parameters ---------- objname: str Solar system object name. Current support solar system bodies are listed in astropy.coordinates.solar_system_ephemeris.bodies attribution. t: Astropy.time.Time object Observation time in Astropy.time.Time object format. ephem: str The ephem to for computing solar system object position and velocity path : str, optional Local path to the ephemeris file. link : str, optional Location of path on the internet. Returns ------- PosVel object with 3-vectors for the position and velocity of the object """ objname = objname.lower() load_kernel(ephem, path=path, link=link) pos, vel = coor.get_body_barycentric_posvel(objname, t) return PosVel(pos.xyz, vel.xyz.to(u.km / u.second), origin='ssb', obj=objname)
def _get_state(body, time): """ Computes the position of a body for a given time. """ solar_system_bodies = [ Sun, Mercury, Venus, Earth, Moon, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, ] # We check if body belongs to poliastro.bodies if body in solar_system_bodies: rr, vv = coord.get_body_barycentric_posvel(body.name, time) else: rr, vv = body.propagate(time).rv() rr = coord.CartesianRepresentation(rr) vv = coord.CartesianRepresentation(vv) return rr, vv
def icrs_to_cb_crs(icrs_coord, cb_crs_frame): """Conversion from ICRS to Celestial Reference System of a Central Body.""" if not u.m.is_equivalent(icrs_coord.cartesian.x.unit): raise u.UnitsError( _NEED_ORIGIN_HINT.format(icrs_coord.__class__.__name__)) if icrs_coord.data.differentials: # Calculate the barycentric position and velocity (of a solar system body). # Uses default ephemeris r_icrs, v_icrs = get_body_barycentric_posvel( cb_crs_frame.body_name, cb_crs_frame.obstime, ephemeris=cb_crs_frame.ephemeris_type, ) v_icrs = CartesianDifferential.from_cartesian(v_icrs) # Prepare final coord vector with velocity cb_crs_coord = (-r_icrs).with_differentials(-v_icrs) else: # Calculate the barycentric position ONLY (of a solar system body). # Uses default ephemeris. This is faster than the one above with velocities for # JPL ephemerides. cb_crs_coord = -get_body_barycentric( cb_crs_frame.body_name, cb_crs_frame.obstime, ephemeris=cb_crs_frame.ephemeris_type, ) # Return transformation matrix (None) and translation vector (with velocities) return None, cb_crs_coord
def get_earth_velocity(mjds, raj, decj): """ Calculates the component of Earth's velocity transverse to the line of sight, in RA and DEC """ from astropy.time import Time from astropy.coordinates import get_body_barycentric_posvel, SkyCoord from astropy import units as u from astropy.constants import au coord = SkyCoord('{0} {1}'.format(raj, decj), unit=(u.hourangle, u.deg)) rarad = coord.ra.value * np.pi / 180 decrad = coord.dec.value * np.pi / 180 vearth_ra = [] vearth_dec = [] for mjd in mjds: time = Time(mjd, format='mjd') pos_xyz, vel_xyz = get_body_barycentric_posvel('earth', time) vx = vel_xyz.x.value vy = vel_xyz.y.value vz = vel_xyz.z.value vearth_ra.append(-vx * np.sin(rarad) + vy * np.cos(rarad)) vearth_dec.append(-vx * np.sin(decrad) * np.cos(rarad) - vy * np.sin(decrad) * np.sin(rarad) + vz * np.cos(decrad)) # Convert from AU/d to km/s vearth_ra = vearth_ra * au / 1e3 / 86400 vearth_dec = vearth_dec * au / 1e3 / 86400 return vearth_ra.value.squeeze(), vearth_dec.value.squeeze()
def to_equatorial(fixed_coo, equatorial_frame): assert fixed_coo.body == equatorial_frame.body r = fixed_coo.data.xyz v = fixed_coo.data.differentials["s"].d_xyz ra, dec, W = fixed_coo.rot_elements_at_epoch(fixed_coo.obstime) r = transform_vector(r, -W, "z") v = transform_vector(v, -W, "z") r_trans1 = transform_vector(r, -(90 * u.deg - dec), "x") r_trans2 = transform_vector(r_trans1, -(90 * u.deg + ra), "z") v_trans1 = transform_vector(v, -(90 * u.deg - dec), "x") v_trans2 = transform_vector(v_trans1, -(90 * u.deg + ra), "z") icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel( fixed_coo.body.name, time=fixed_coo.obstime) r_f = icrs_frame_pos_coord.xyz + r_trans2 v_f = icrs_frame_vel_coord.xyz + v_trans2 data = CartesianRepresentation( r_f, differentials=CartesianDifferential(v_f)) return equatorial_frame.realize_frame(data)
def from_equatorial(equatorial_coo, fixed_frame): assert equatorial_coo.body == fixed_frame.body r = equatorial_coo.data.xyz v = equatorial_coo.data.differentials["s"].d_xyz ra, dec, W = fixed_frame.rot_elements_at_epoch(equatorial_coo.obstime) icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel( equatorial_coo.body.name, time=equatorial_coo.obstime) r_trans1 = r - icrs_frame_pos_coord.xyz r_trans2 = transform_vector(r_trans1, (90 * u.deg + ra), "z") r_f = transform_vector(r_trans2, (90 * u.deg - dec), "x") v_trans1 = v - icrs_frame_vel_coord.xyz v_trans2 = transform_vector(v_trans1, (90 * u.deg + ra), "z") v_f = transform_vector(v_trans2, (90 * u.deg - dec), "x") r_f = transform_vector(r_f, W, "z") v_f = transform_vector(v_f, W, "z") data = CartesianRepresentation( r_f, differentials=CartesianDifferential(v_f)) return fixed_frame.realize_frame(data)
def _get_moon_altitudes(self, time, pos): # get current moon moon_loc, moon_vel = get_body_barycentric_posvel('moon', time) moon_loc = SkyCoord(representation_type='cartesian', differential_type=CartesianDifferential, unit='m', frame='icrs', obstime=time, x=moon_loc.x, y=moon_loc.y, z=moon_loc.z, v_x=moon_vel.x, v_y=moon_vel.y, v_z=moon_vel.z) moon = moon_loc.transform_to(GCRS(obstime=time)) # get current receiver receiver_loc, receiver_vel = pos.get_gcrs_posvel(time) receiver = SkyCoord(representation_type='cartesian', differential_type=CartesianDifferential, unit='m', frame='gcrs', obstime=time, x=receiver_loc.x, y=receiver_loc.y, z=receiver_loc.z, v_x=receiver_vel.x, v_y=receiver_vel.y, v_z=receiver_vel.z) moon_altaz = moon.transform_to(AltAz(obstime=time, location=receiver)) return moon_altaz.alt
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ # TODO: https://github.com/poliastro/poliastro/issues/445 if not epoch: epoch = time.Time.now().tdb elif epoch.scale != 'tdb': epoch = epoch.tdb warn("Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead." .format(epoch.tdb.value), TimeScaleWarning) r, v = get_body_barycentric_posvel(body.name, epoch) if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials(v.represent_as(CartesianDifferential)) gcrs_cart = ICRS(icrs_cart).transform_to(GCRS(obstime=epoch)).represent_as(CartesianRepresentation) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials['s'].d_xyz.to(u.km / u.day), epoch ) else: # TODO: The attractor is not really the Sun, but the Solar System Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def objPosVel_wrt_SSB(objname, t, ephem, path=None, link=None): """This function computes a solar system object position and velocity respect to solar system barycenter using astropy coordinates get_body_barycentric() method. The coordinate frame is that of the underlying solar system ephemeris, which has been the ICRF (J2000) since the DE4XX series. Parameters ---------- objname: str Solar system object name. Current support solar system bodies are listed in astropy.coordinates.solar_system_ephemeris.bodies attribution. t: Astropy.time.Time object Observation time in Astropy.time.Time object format. ephem: str The ephem to for computing solar system object position and velocity path: str optional The data directory point to a local ephemeris. link: str optional The link where to download the ephemeris. Returns ------- PosVel object with 3-vectors for the position and velocity of the object Note ---- If both path and link are provided. Path will be first to try. """ ephem = ephem.lower() objname = objname.lower() # Use astropy to compute postion. # If a local path is provided, the local search will be considered first. # If the path is not provided, try link first, then local data file. if path is None: if link is None: link_str = '' else: link_str = link is_load = _load_kernel_link(ephem, link=link_str) if not is_load: # Link does not Try to load from data path. path_str = '' is_load = _load_kernel_local(ephem, path=path_str) if not is_load: raise ValueError("Can not load the ephemeris file '%s.bsp'. " % ephem) else: path_str = path is_load = _load_kernel_local(ephem, path=path_str) if not is_load: raise ValueError( "Can not load the ephemeris file '%s.bsp' from the" " local directory %s." % (ephem, path_str)) pos, vel = coor.get_body_barycentric_posvel(objname, t) return PosVel(pos.xyz, vel.xyz.to(u.km / u.second), origin='ssb', obj=objname)
def get_barycentric_vel(self, t, t0=None, tformat=None): if tformat is None: tformat = self.unitc.tname if tformat == 'jd' and t0 is None: t0 = 2451545 # jan 1 2000 in jd t_ = Time(t + t0, format=tformat) vel = get_body_barycentric_posvel(self.name, t_)[1].xyz.to( self.unitc.vname).to_value() return vel
def get_body(times, body, savefile=False): tab = Table() t= Table(names=['utc', 'jd', 'x', 'y', 'z', 'd', 'vx', 'vy', 'vz', 'v'], dtype=['S32', 'f16', 'f16', 'f16', 'f16', 'f16', 'f16', 'f16', 'f16', 'f16']) for time in times: pos, vel = get_body_barycentric_posvel(body, time, ephemeris='de430') t.add_row([time.value, time.jd, pos.x.value, pos.y.value, pos.z.value, pos.norm().value, vel.x.value/(u.day.to(u.second)), vel.y.value/(u.day.to(u.second)), vel.z.value/(u.day.to(u.second)), vel.norm().value/(u.day.to(u.second))]) if savefile==True: t.write('/home/akash/results/{b}_Ephemeride.txt'.format(b=body), format='ascii', delimiter='\t', overwrite=True) return t
def __call__(self, t, u_, k): # Solve for primary and secondary bodies position w.r.t. solar system # barycenter at a particular epoch. (r_primary_wrt_ssb, _), (r_secondary_wrt_ssb, _) = [ get_body_barycentric_posvel(body.name, self._epoch + t * u.s) for body in (self._primary_body, self._secondary_body) ] r_sec = ((r_secondary_wrt_ssb - r_primary_wrt_ssb).xyz << u.km).value return r_sec
def objPosVel_wrt_SSB(objname, t, ephem, path=None, link=None): """This function computes a solar system object position and velocity respect to solar system barycenter using astropy coordinates get_body_barycentric() method. The coordinate frame is that of the underlying solar system ephemeris, which has been the ICRF (J2000) since the DE4XX series. Parameters ---------- objname: str Solar system object name. Current support solar system bodies are listed in astropy.coordinates.solar_system_ephemeris.bodies attribution. t: Astropy.time.Time object Observation time in Astropy.time.Time object format. ephem: str The ephem to for computing solar system object position and velocity path: str optional The data directory point to a local ephemeris. link: str optional The link where to download the ephemeris. Returns ------- PosVel object with 3-vectors for the position and velocity of the object Note ---- If both path and link are provided. Path will be first to try. """ ephem = ephem.lower() objname = objname.lower() # Use astropy to compute postion. # If a local path is provided, the local search will be considered first. # If the path is not provided, try link first, then local data file. if path is None: if link is None: link_str = '' else: link_str = link is_load = _load_kernel_link(ephem, link=link_str) if not is_load: # Link does not Try to load from data path. path_str = '' is_load = _load_kernel_local(ephem, path=path_str) if not is_load: raise ValueError("Can not load the ephemeris file '%s.bsp'. " % ephem) else: path_str = path is_load = _load_kernel_local(ephem, path=path_str) if not is_load: raise ValueError("Can not load the ephemeris file '%s.bsp' from the" " local directory %s." % (ephem, path_str)) pos, vel = coor.get_body_barycentric_posvel(objname, t) return PosVel(pos.xyz, vel.xyz.to(u.km/u.second), origin='ssb', obj=objname)
def get_coord_list(self, time_list, velocity=False, ephemeris="builtin"): """ Computes the set of positions (and velocities, if requested) of the Celestial Body in the `ICRS` frame. Any further frame transformations can then be carried out. Default ephemeris is `builtin`, though it cannot compute the velocity for the Moon. Ephemeris can also be `jpl`, where the default implementation in Astropy is used. Be warned that the first time this is called, a large file has to be downloaded. Parameters ---------- time_list : `~astropy.time.Time` List of times where position output is requested velocity : bool True if velocities are of the celestial body is also requested ephemeris : str, optional Ephemeris to use. By default, use the one set with ``astropy.coordinates.solar_system_ephemeris.set`` Returns ------- SkyCoord Set of cartesian positions (and velocities) in a `SkyCoord` object """ if velocity: r, v = get_body_barycentric_posvel(self.name, time_list, ephemeris=ephemeris) v_body = CartesianDifferential(v.xyz) r_body = r.with_differentials(v_body) coord_list = SkyCoord( r_body.with_differentials(v_body), obstime=time_list, frame="icrs", representation_type="cartesian", differential_type="cartesian", ) else: coord_list = SkyCoord( get_body_barycentric(self.name, time_list, ephemeris=ephemeris), obstime=time_list, frame="icrs", representation_type="cartesian", differential_type="cartesian", ) return coord_list
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ from poliastro.bodies import Earth, Moon, Sun warn( "Orbit.from_body_ephem is deprecated and will be removed in a future release, " "see https://github.com/poliastro/poliastro/issues/445 for discussion.", DeprecationWarning, stacklevel=2, ) if not epoch: epoch = time.Time.now().tdb elif epoch.scale != "tdb": epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " f"{epoch.tdb.value}. Use Time(..., scale='tdb') instead.", TimeScaleWarning, stacklevel=2, ) try: r, v = get_body_barycentric_posvel(body.name, epoch) except KeyError as exc: raise RuntimeError( """To compute the position and velocity of the Moon and Pluto use the JPL ephemeris: >>> from astropy.coordinates import solar_system_ephemeris >>> solar_system_ephemeris.set('jpl') """) from exc if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials( v.represent_as(CartesianDifferential)) gcrs_cart = (ICRS(icrs_cart).transform_to( GCRS(obstime=epoch)).represent_as(CartesianRepresentation)) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials["s"].d_xyz.to(u.km / u.day), epoch, ) else: # TODO: The attractor is not really the Sun, but the Solar System # Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def transit(date, date_arrival, planet1, planet2): #czas trwania misji tof = date_arrival - date N = 50 tof.to(u.h) times_vector = time_range(date, end=date_arrival, periods=N) # okreslenie pozycji planet w przedziale czasu: od startu do końca misji rr_planet1, vv_planet1 = get_body_barycentric_posvel(planet1, times_vector) rr_planet2, vv_planet2 = get_body_barycentric_posvel(planet2, times_vector) r0 = rr_planet1[0].xyz #wektor pozycji Ziemi w momencie startu v0 = vv_planet1[0].xyz #wektor predkosci Ziemi w momencie startu rf = rr_planet2[ -1].xyz #wektor pozycji planety docelowej w momencie końca misji vf = vv_planet2[ -1].xyz #wektor predkosci planety docelowej w momencie końca misji # rozwiazanie problemu Lamberta (va, vb), = iod.lambert(Sun.k, r0, rf, tof, numiter=1000) return (r0, v0, rf, vf, va, vb, rr_planet1, rr_planet2, times_vector)
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ if not epoch: epoch = time.Time.now().tdb elif epoch.scale != 'tdb': epoch = epoch.tdb warn("Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead." .format(epoch.tdb.value), TimeScaleWarning) r, v = get_body_barycentric_posvel(body.name, epoch) return cls.from_vectors(body.parent, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch)
def test_velocity_hcrs_hgs(): # Obtain the position/velocity of Earth in ICRS obstime = Time(['2019-01-01', '2019-04-01', '2019-07-01', '2019-10-01']) pos, vel = get_body_barycentric_posvel('earth', obstime) loc = pos.with_differentials(vel.represent_as(CartesianDifferential)) earth = SkyCoord(loc, frame='icrs', obstime=obstime) # The velocity of Earth in HGS Y should be very close to zero because the XZ plane tracks # the Earth. new = earth.heliographic_stonyhurst assert_quantity_allclose(new.velocity.d_y, 0*u.km/u.s, atol=1e-5*u.km/u.s) # Test the loopback to ICRS newer = new.icrs assert_quantity_allclose(newer.velocity.d_xyz, vel.xyz)
def body_centered_to_icrs(r, v, source_body, epoch=J2000, rotate_meridian=False): """Converts position and velocity body-centered frame to ICRS. Parameters ---------- r : ~astropy.units.Quantity Position vector in a body-centered reference frame. v : ~astropy.units.Quantity Velocity vector in a body-centered reference frame. source_body : Body Source body. epoch : ~astropy.time.Time, optional Epoch, default to J2000. rotate_meridian : bool, optional Whether to apply the rotation of the meridian too, default to False. Returns ------- r, v : tuple (~astropy.units.Quantity) Position and velocity vectors in ICRS. """ ra, dec, W = source_body.rot_elements_at_epoch(epoch) if rotate_meridian: r = transform(r, -W, 'z') v = transform(v, -W, 'z') r_trans1 = transform(r, -(90 * u.deg - dec), 'x') r_trans2 = transform(r_trans1, -(90 * u.deg + ra), 'z') v_trans1 = transform(v, -(90 * u.deg - dec), 'x') v_trans2 = transform(v_trans1, -(90 * u.deg + ra), 'z') icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel( source_body.name, time=epoch) r_f = icrs_frame_pos_coord.xyz + r_trans2 v_f = icrs_frame_vel_coord.xyz + v_trans2 return r_f.to(r.unit), v_f.to(v.unit)
def icrs_to_body_centered(r, v, target_body, epoch=J2000, rotate_meridian=False): """Converts position and velocity in ICRS to body-centered frame. Parameters ---------- r : ~astropy.units.Quantity Position vector in ICRS. v : ~astropy.units.Quantity Velocity vector in ICRS. target_body : Body Target body. epoch : ~astropy.time.Time, optional Epoch, default to J2000. rotate_meridian : bool, optional Whether to apply the rotation of the meridian too, default to False. Returns ------- r, v : tuple (~astropy.units.Quantity) Position and velocity vectors in a body-centered reference frame. """ ra, dec, W = target_body.rot_elements_at_epoch(epoch) icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel( target_body.name, time=epoch) r_trans1 = r - icrs_frame_pos_coord.xyz r_trans2 = transform(r_trans1, (90 * u.deg + ra), 'z') r_f = transform(r_trans2, (90 * u.deg - dec), 'x') v_trans1 = v - icrs_frame_vel_coord.xyz v_trans2 = transform(v_trans1, (90 * u.deg + ra), 'z') v_f = transform(v_trans2, (90 * u.deg - dec), 'x') if rotate_meridian: r_f = transform(r_f, W, 'z') v_f = transform(v_f, W, 'z') return r_f.to(r.unit), v_f.to(v.unit)
def from_body(cls, body, epochs, *, attractor=None, plane=Planes.EARTH_EQUATOR): """Return `Ephem` for a `SolarSystemPlanet` at certain epochs. Parameters ---------- body: ~poliastro.bodies.SolarSystemPlanet Body. epochs: ~astropy.time.Time Epochs to sample the body positions. attractor : ~poliastro.bodies.SolarSystemPlanet, optional Body to use as central location, if not given the Solar System Barycenter will be used. plane : ~poliastro.frames.Planes, optional Fundamental plane of the frame, default to Earth Equator. """ if epochs.isscalar: epochs = epochs.reshape(1) if epochs.scale != "tdb": epochs = epochs.tdb warn( "Input time was converted to scale='tdb' with value " f"{epochs.tdb.value}. Use Time(..., scale='tdb') instead.", TimeScaleWarning, stacklevel=2, ) r, v = get_body_barycentric_posvel(body.name, epochs) coordinates = r.with_differentials( v.represent_as(CartesianDifferential)) destination_frame = _get_destination_frame(attractor, plane, epochs) if destination_frame is not None: coordinates = ( ICRS(coordinates).transform_to(destination_frame).represent_as( CartesianRepresentation, CartesianDifferential)) return cls(coordinates, epochs, plane)
def test_spectral_coord_jupiter(): """ Checks radial velocity between Earth and Jupiter """ obstime = time.Time('2018-12-13 9:00') obs = get_greenwich_earthlocation().get_gcrs(obstime) pos, vel = get_body_barycentric_posvel('jupiter', obstime) jupiter = SkyCoord(pos.with_differentials(CartesianDifferential(vel.xyz)), obstime=obstime) spc = SpectralCoord([100, 200, 300] * u.nm, observer=obs, target=jupiter) # The velocity should be less than ~43 + a bit extra, which is the # maximum possible earth-jupiter relative velocity. We check the exact # value here (determined from SpectralCoord, so this serves as a test to # check that this value doesn't change - the value is not a ground truth) assert_quantity_allclose(spc.radial_velocity, -7.35219854 * u.km / u.s)
def to_icrs(planet_coo, _): # this is just an origin translation so without a distance it cannot go ahead if isinstance(planet_coo.data, UnitSphericalRepresentation): raise u.UnitsError( _NEED_ORIGIN_HINT.format(planet_coo.__class__.__name__)) if planet_coo.data.differentials: bary_sun_pos, bary_sun_vel = get_body_barycentric_posvel( planet_coo.body.name, planet_coo.obstime) bary_sun_pos = bary_sun_pos.with_differentials( bary_sun_vel.represent_as(CartesianDifferential)) else: bary_sun_pos = get_body_barycentric(planet_coo.body.name, planet_coo.obstime) bary_sun_vel = None return None, bary_sun_pos
def R(time, vel=False): # R is the position vector of Earth # requires an astropy Time object # returns R, a three component array describing the position vector of Earth # in au _R, _Rdot = get_body_barycentric_posvel('earth', time, ephemeris='jpl') c = vector( _R.x.to(u.AU) / u.AU, _R.y.to(u.AU) / u.AU, _R.z.to(u.AU) / u.AU) if vel: d = vector( _Rdot.x.to(u.AU / u.d) / (u.AU / u.d), _Rdot.y.to(u.AU / u.d) / (u.AU / u.d), _Rdot.z.to(u.AU / u.d) / (u.AU / u.d)) return c, d else: return c
def compute_l2_pos_and_vel(time0: astropy.time.Time, earth_l2_distance_km: float = EARTH_L2_DISTANCE_KM): """ Compute the position and velocity of the L2 Sun-Earth point at a given time. The L2 point is not calculated using Lagrange's equations; instead, its distance from the Earth must be provided as the parameter `earth_l2_distance_km`. The default value is a reasonable estimate. The L2 point is assumed to lie along the line that connects the Solar System Barycenter with the Earth's gravitational center. The return value is a 2-tuple containing two NumPy arrays: 1. A 3D array containing the XYZ components of the vector specifying the position of the L2 point, in km 2. A 3D array containing the XYZ components of the velocity vector of the L2 point, in km/s The two vectors are always roughly perpendicular, but they are not exactly due to the irregular motion of the Earth (caused by gravitational interactions with other Solar System bodies, like the Moon and Jupiter). """ # Use # # solar_system_ephemeris.set("builtin") # # to make AstroPy use the built-in ephemeris table earth_pos, earth_vel = get_body_barycentric_posvel("earth", time0) earth_pos = ICRS(earth_pos).transform_to( DEFAULT_COORDINATE_SYSTEM).cartesian earth_vel = ICRS(earth_vel).transform_to( DEFAULT_COORDINATE_SYSTEM).cartesian fudge_factor = earth_l2_distance_km / earth_pos.norm().to("km").value # Move from Earth to L2 l2_pos = earth_pos * (1.0 + fudge_factor) l2_vel = earth_vel * (1.0 + fudge_factor) return ( l2_pos.xyz.to("km").value.transpose(), l2_vel.xyz.to("km/s").value.transpose(), )
def from_icrs(icrs_coo, planet_frame): # this is just an origin translation so without a distance it cannot go ahead if isinstance(icrs_coo.data, UnitSphericalRepresentation): raise u.UnitsError( _NEED_ORIGIN_HINT.format(icrs_coo.__class__.__name__)) if icrs_coo.data.differentials: bary_sun_pos, bary_sun_vel = get_body_barycentric_posvel( planet_frame.body.name, planet_frame.obstime) # Beware! Negation operation is not supported for differentials bary_sun_pos = (-bary_sun_pos).with_differentials( -bary_sun_vel.represent_as(CartesianDifferential)) else: bary_sun_pos = -get_body_barycentric(planet_frame.body.name, planet_frame.obstime) bary_sun_vel = None return None, bary_sun_pos
def from_body_ephem(cls, body, epoch=None): """Return osculating `Orbit` of a body at a given time. """ # TODO: https://github.com/poliastro/poliastro/issues/445 if not epoch: epoch = time.Time.now().tdb elif epoch.scale != "tdb": epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " "{}. Use Time(..., scale='tdb') instead.".format(epoch.tdb.value), TimeScaleWarning, ) try: r, v = get_body_barycentric_posvel(body.name, epoch) except KeyError: raise RuntimeError( "To compute the position and velocity of the Moon and Pluto use the JPL ephemeris:\n>>>from astropy.coordinates import solar_system_ephemeris\n>>>solar_system_ephemeris.set('jpl')" ) if body == Moon: # TODO: The attractor is in fact the Earth-Moon Barycenter icrs_cart = r.with_differentials(v.represent_as(CartesianDifferential)) gcrs_cart = ( ICRS(icrs_cart) .transform_to(GCRS(obstime=epoch)) .represent_as(CartesianRepresentation) ) ss = cls.from_vectors( Earth, gcrs_cart.xyz.to(u.km), gcrs_cart.differentials["s"].d_xyz.to(u.km / u.day), epoch, ) else: # TODO: The attractor is not really the Sun, but the Solar System # Barycenter ss = cls.from_vectors(Sun, r.xyz.to(u.km), v.xyz.to(u.km / u.day), epoch) ss._frame = ICRS() # Hack! return ss
def to_icrs(planet_coo, _): # this is just an origin translation so without a distance it cannot go ahead if isinstance(planet_coo.data, UnitSphericalRepresentation): raise u.UnitsError(_NEED_ORIGIN_HINT.format(planet_coo.__class__.__name__)) if planet_coo.data.differentials: bary_sun_pos, bary_sun_vel = get_body_barycentric_posvel( planet_coo.body.name, planet_coo.obstime ) bary_sun_pos = bary_sun_pos.with_differentials( bary_sun_vel.represent_as(CartesianDifferential) ) else: bary_sun_pos = get_body_barycentric( planet_coo.body.name, planet_coo.obstime ) bary_sun_vel = None return None, bary_sun_pos
def body_centered_to_icrs(r, v, source_body, epoch=J2000, rotate_meridian=False): """Converts position and velocity body-centered frame to ICRS. Parameters ---------- r : ~astropy.units.Quantity Position vector in a body-centered reference frame. v : ~astropy.units.Quantity Velocity vector in a body-centered reference frame. source_body : Body Source body. epoch : ~astropy.time.Time, optional Epoch, default to J2000. rotate_meridian : bool, optional Whether to apply the rotation of the meridian too, default to False. Returns ------- r, v : tuple (~astropy.units.Quantity) Position and velocity vectors in ICRS. """ ra, dec, W = source_body.rot_elements_at_epoch(epoch) if rotate_meridian: r = transform_vector(r, -W, 'z') v = transform_vector(v, -W, 'z') r_trans1 = transform_vector(r, -(90 * u.deg - dec), 'x') r_trans2 = transform_vector(r_trans1, -(90 * u.deg + ra), 'z') v_trans1 = transform_vector(v, -(90 * u.deg - dec), 'x') v_trans2 = transform_vector(v_trans1, -(90 * u.deg + ra), 'z') icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel(source_body.name, time=epoch) r_f = icrs_frame_pos_coord.xyz + r_trans2 v_f = icrs_frame_vel_coord.xyz + v_trans2 return r_f.to(r.unit), v_f.to(v.unit)
def from_icrs(icrs_coo, planet_frame): # this is just an origin translation so without a distance it cannot go ahead if isinstance(icrs_coo.data, UnitSphericalRepresentation): raise u.UnitsError(_NEED_ORIGIN_HINT.format(icrs_coo.__class__.__name__)) if icrs_coo.data.differentials: bary_sun_pos, bary_sun_vel = get_body_barycentric_posvel( planet_frame.body.name, planet_frame.obstime ) # Beware! Negation operation is not supported for differentials bary_sun_pos = (-bary_sun_pos).with_differentials( -bary_sun_vel.represent_as(CartesianDifferential) ) else: bary_sun_pos = -get_body_barycentric( planet_frame.body.name, planet_frame.obstime ) bary_sun_vel = None return None, bary_sun_pos
def icrs_to_body_centered(r, v, target_body, epoch=J2000, rotate_meridian=False): """Converts position and velocity in ICRS to body-centered frame. Parameters ---------- r : ~astropy.units.Quantity Position vector in ICRS. v : ~astropy.units.Quantity Velocity vector in ICRS. target_body : Body Target body. epoch : ~astropy.time.Time, optional Epoch, default to J2000. rotate_meridian : bool, optional Whether to apply the rotation of the meridian too, default to False. Returns ------- r, v : tuple (~astropy.units.Quantity) Position and velocity vectors in a body-centered reference frame. """ ra, dec, W = target_body.rot_elements_at_epoch(epoch) icrs_frame_pos_coord, icrs_frame_vel_coord = get_body_barycentric_posvel(target_body.name, time=epoch) r_trans1 = r - icrs_frame_pos_coord.xyz r_trans2 = transform_vector(r_trans1, (90 * u.deg + ra), 'z') r_f = transform_vector(r_trans2, (90 * u.deg - dec), 'x') v_trans1 = v - icrs_frame_vel_coord.xyz v_trans2 = transform_vector(v_trans1, (90 * u.deg + ra), 'z') v_f = transform_vector(v_trans2, (90 * u.deg - dec), 'x') if rotate_meridian: r_f = transform_vector(r_f, W, 'z') v_f = transform_vector(v_f, W, 'z') return r_f.to(r.unit), v_f.to(v.unit)
Exception("Could not parse time interval: {}".format(args.interval)) # set the end time try: endtime = Time(starttime.decimalyear + args.nyears, format='decimalyear', scale='utc') + dt except ValueError: Exception("Could not parse total timespan") pos = [] vel = [] acc = [] # get positions, velocities and accelerations curtime = starttime while curtime <= endtime: tpos, tvel = get_body_barycentric_posvel(body, curtime) # convert positions to light seconds pos.append(tpos.xyz.to('m')/const.c) # convert velocities to light seconds per second vel.append(tvel.xyz.to('m/s')/const.c) # calculate accelerations (using velocities +/- dt/2 around the current time) ctminus = curtime - dt/2. _, mvel = get_body_barycentric_posvel(body, ctminus) ctplus = curtime + dt/2. _, pvel = get_body_barycentric_posvel(body, ctplus) acc.append(((pvel.xyz.to('m/s')-mvel.xyz.to('m/s'))/const.c)/dt.to('s')) curtime += dt