def get_mean_elements(body, epoch=J2000): """Get ecliptic mean elements of body. Parameters ---------- body : ~poliastro.bodies.SolarSystemPlanet Body. epoch : astropy.time.Time Epoch. """ # Internally, erfa.plan94 has a table of classical elements, # which are then converted to position and velocity... # So we are reverting the conversion in the last line # This way at least we avoid copy pasting the values try: name = body.name.lower() if name == "earth": name = "earth-moon-barycenter" body_index = PLAN94_BODY_NAME_TO_PLANET_INDEX[name] body_pv_helio = erfa.plan94(epoch.jd1, epoch.jd2, body_index) r = body_pv_helio["p"] * u.au v = body_pv_helio["v"] * u.au / u.day except KeyError as e: raise ValueError( f"No available mean elements for {body}. It must be an instance of `poliastro.bodies.SolarSystemPlanet`" ) from e return RVState(body.parent, r, v, plane=Planes.EARTH_ECLIPTIC).to_classical()
def __init__(self, utc, longitude, latitude, altitude): try: super().__init__(utc, longitude, latitude, altitude) except TypeError: super(Ephem, self).__init__(utc, longitude, latitude, altitude) # julian centuries at the given UTC self.jc = (self.tdb1+self.tdb2-erfa.DJ00)/erfa.DJC # heliocentric position of major bodies self.p94 = [erfa.plan94(self.tdb1, self.tdb2, i) for i in range(1,9)] # Earth heliocentric position and velocity self.eph, self.epb = erfa.epv00(self.tdb1, self.tdb2) self.distances_from_earth = {} self.RA_DEC = {} ## # precession angles ## eps0,psia,oma,bpa,bqa,pia,bpia,epsa,chia,za,zetaa,thetaa,pa,gam,phi,psi = erfa.p06e(self.tt1, self.tt2) ## ## # Fundamental argument of major bodies ## mer = erfa.fame03(self.jc)) self.sun() self.planets()
def _get_body_barycentric_posvel(body, time, ephemeris=None, get_velocity=True): """Calculate the barycentric position (and velocity) of a solar system body. Parameters ---------- body : str or other The solar system body for which to calculate positions. Can also be a kernel specifier (list of 2-tuples) if the ``ephemeris`` is a JPL kernel. time : `~astropy.time.Time` Time of observation. ephemeris : str, optional Ephemeris to use. By default, use the one set with ``astropy.coordinates.solar_system_ephemeris.set`` get_velocity : bool, optional Whether or not to calculate the velocity as well as the position. Returns ------- position : `~astropy.coordinates.CartesianRepresentation` or tuple Barycentric (ICRS) position or tuple of position and velocity. Notes ----- No velocity can be calculated with the built-in ephemeris for the Moon. Whether or not velocities are calculated makes little difference for the built-in ephemerides, but for most JPL ephemeris files, the execution time roughly doubles. """ if ephemeris is None: ephemeris = solar_system_ephemeris.get() if ephemeris is None: raise ValueError(_EPHEMERIS_NOTE) kernel = solar_system_ephemeris.kernel else: kernel = _get_kernel(ephemeris) jd1, jd2 = get_jd12(time, 'tdb') if kernel is None: body = body.lower() earth_pv_helio, earth_pv_bary = erfa.epv00(jd1, jd2) if body == 'earth': body_pv_bary = earth_pv_bary elif body == 'moon': if get_velocity: raise KeyError("the Moon's velocity cannot be calculated with " "the '{}' ephemeris.".format(ephemeris)) return calc_moon(time).cartesian else: sun_pv_bary = erfa.pvmpv(earth_pv_bary, earth_pv_helio) if body == 'sun': body_pv_bary = sun_pv_bary else: try: body_index = PLAN94_BODY_NAME_TO_PLANET_INDEX[body] except KeyError: raise KeyError( "{}'s position and velocity cannot be " "calculated with the '{}' ephemeris.".format( body, ephemeris)) body_pv_helio = erfa.plan94(jd1, jd2, body_index) body_pv_bary = erfa.pvppv(body_pv_helio, sun_pv_bary) body_pos_bary = CartesianRepresentation(body_pv_bary['p'], unit=u.au, xyz_axis=-1, copy=False) if get_velocity: body_vel_bary = CartesianRepresentation(body_pv_bary['v'], unit=u.au / u.day, xyz_axis=-1, copy=False) else: if isinstance(body, str): # Look up kernel chain for JPL ephemeris, based on name try: kernel_spec = BODY_NAME_TO_KERNEL_SPEC[body.lower()] except KeyError: raise KeyError("{}'s position cannot be calculated with " "the {} ephemeris.".format(body, ephemeris)) else: # otherwise, assume the user knows what their doing and intentionally # passed in a kernel chain kernel_spec = body # jplephem cannot handle multi-D arrays, so convert to 1D here. jd1_shape = getattr(jd1, 'shape', ()) if len(jd1_shape) > 1: jd1, jd2 = jd1.ravel(), jd2.ravel() # Note that we use the new jd1.shape here to create a 1D result array. # It is reshaped below. body_posvel_bary = np.zeros((2 if get_velocity else 1, 3) + getattr(jd1, 'shape', ())) for pair in kernel_spec: spk = kernel[pair] if spk.data_type == 3: # Type 3 kernels contain both position and velocity. posvel = spk.compute(jd1, jd2) if get_velocity: body_posvel_bary += posvel.reshape(body_posvel_bary.shape) else: body_posvel_bary[0] += posvel[:4] else: # spk.generate first yields the position and then the # derivative. If no velocities are desired, body_posvel_bary # has only one element and thus the loop ends after a single # iteration, avoiding the velocity calculation. for body_p_or_v, p_or_v in zip(body_posvel_bary, spk.generate(jd1, jd2)): body_p_or_v += p_or_v body_posvel_bary.shape = body_posvel_bary.shape[:2] + jd1_shape body_pos_bary = CartesianRepresentation(body_posvel_bary[0], unit=u.km, copy=False) if get_velocity: body_vel_bary = CartesianRepresentation(body_posvel_bary[1], unit=u.km / u.day, copy=False) return (body_pos_bary, body_vel_bary) if get_velocity else body_pos_bary