def _obs_pos(self): '''calculates heliocentric and barycentric position of the earth in AU and AU/d''' tdb = self.tdb # get heliocentric and barycentric position and velocity of Earth # BCRS reference frame h_pv,b_pv = erfa.epv00(tdb.jd1,tdb.jd2) # h_pv etc can be shape (ntimes,2,3) or (2,3) if given a scalar time if h_pv.ndim == 2: h_pv = h_pv[np.newaxis,:] if b_pv.ndim == 2: b_pv = b_pv[np.newaxis,:] # unpack into position and velocity arrays h_pos = h_pv[:,0,:] h_vel = h_pv[:,1,:] # unpack into position and velocity arrays b_pos = b_pv[:,0,:] b_vel = b_pv[:,1,:] #now need position and velocity of observing station pos_obs, vel_obs = self._pvobs() #add this to heliocentric and barycentric position of center of Earth h_pos += pos_obs b_pos += pos_obs h_vel += vel_obs b_vel += vel_obs return (h_pos,h_vel,b_pos,b_vel)
def velocity_of_Earth(full_BJD): """ Calculate 3D velocity of Earth for given epoch. If you need velocity projected on the plane of the sky, then use :py:func:`~MulensModel.coordinates.Coordinates.v_Earth_projected` Parameters : full_BJD: *float* Are we fitting for blending flux? If not then blending flux is fixed to 0. Default is the same as :py:func:`MulensModel.fit.Fit.fit_fluxes()`. Returns : velocity: *np.ndarray* (*float*, size of (3,)) 3D velocity in km/s. The frame follows *Astropy* conventions. """ # The 4 lines below, that calculate velocity for given epoch, # are based on astropy 1.3 code: # https://github.com/astropy/astropy/blob/master/astropy/ # coordinates/solar_system.py time = Time(full_BJD, format='jd', scale='tdb') (jd1, jd2) = get_jd12(time, 'tdb') (earth_pv_helio, earth_pv_bary) = erfa.epv00(jd1, jd2) factor = 1731.45683 # This scales AU/day to km/s. # The returned values are of np.ndarray type in astropy v1 and v2, # but np.void in v3. The np.asarray() works in both cases. velocity = np.asarray(earth_pv_bary[1]) * factor return velocity
def _obs_pos(self): '''calculates heliocentric and barycentric position of the earth in AU and AU/d''' tdb = self.tdb # get heliocentric and barycentric position and velocity of Earth # BCRS reference frame h_pv, b_pv = erfa.epv00(tdb.jd1, tdb.jd2) # h_pv etc can be shape (ntimes,2,3) or (2,3) if given a scalar time if h_pv.ndim == 2: h_pv = h_pv[np.newaxis, :] if b_pv.ndim == 2: b_pv = b_pv[np.newaxis, :] # unpack into position and velocity arrays h_pos = h_pv[:, 0, :] h_vel = h_pv[:, 1, :] # unpack into position and velocity arrays b_pos = b_pv[:, 0, :] b_vel = b_pv[:, 1, :] #now need position and velocity of observing station pos_obs, vel_obs = self._pvobs() #add this to heliocentric and barycentric position of center of Earth h_pos += pos_obs b_pos += pos_obs h_vel += vel_obs b_vel += vel_obs return (h_pos, h_vel, b_pos, b_vel)
def test_icrs_altaz_moonish(testframe): """ Check that something expressed in *ICRS* as being moon-like goes to the right AltAz distance """ # we use epv00 instead of get_sun because get_sun includes aberration earth_pv_helio, earth_pv_bary = epv00(*get_jd12(testframe.obstime, 'tdb')) earth_icrs_xyz = earth_pv_bary[0]*u.au moonoffset = [0, 0, MOONDIST.value]*MOONDIST.unit moonish_icrs = ICRS(CartesianRepresentation(earth_icrs_xyz + moonoffset)) moonaa = moonish_icrs.transform_to(testframe) # now check that the distance change is similar to earth radius assert 1000*u.km < np.abs(moonaa.distance - MOONDIST).to(u.au) < 7000*u.km
def test_icrs_altaz_moonish(testframe): """ Check that something expressed in *ICRS* as being moon-like goes to the right AltAz distance """ # we use epv00 instead of get_sun because get_sun includes aberration earth_pv_helio, earth_pv_bary = epv00(*get_jd12(testframe.obstime, 'tdb')) earth_icrs_xyz = earth_pv_bary[0]*u.au moonoffset = [0, 0, MOONDIST.value]*MOONDIST.unit moonish_icrs = ICRS(CartesianRepresentation(earth_icrs_xyz + moonoffset)) moonaa = moonish_icrs.transform_to(testframe) # now check that the distance change is similar to earth radius assert 1000*u.km < np.abs(moonaa.distance - MOONDIST).to(u.au) < 7000*u.km
def get_sun(time): """ Determines the location of the sun at a given time (or times, if the input is an array `~astropy.time.Time` object), in geocentric coordinates. Parameters ---------- time : `~astropy.time.Time` The time(s) at which to compute the location of the sun. Returns ------- newsc : `~astropy.coordinates.SkyCoord` The location of the sun as a `~astropy.coordinates.SkyCoord` in the `~astropy.coordinates.GCRS` frame. Notes ----- The algorithm for determining the sun/earth relative position is based on the simplified version of VSOP2000 that is part of ERFA. Compared to JPL's ephemeris, it should be good to about 4 km (in the Sun-Earth vector) from 1900-2100 C.E., 8 km for the 1800-2200 span, and perhaps 250 km over the 1000-3000. """ earth_pv_helio, earth_pv_bary = erfa.epv00(*get_jd12(time, 'tdb')) # We have to manually do aberration because we're outputting directly into # GCRS earth_p = earth_pv_helio['p'] earth_v = earth_pv_bary['v'] # convert barycentric velocity to units of c, but keep as array for passing in to erfa earth_v /= c.to_value(u.au / u.d) dsun = np.sqrt(np.sum(earth_p**2, axis=-1)) invlorentz = (1 - np.sum(earth_v**2, axis=-1))**0.5 properdir = erfa.ab(earth_p / dsun.reshape(dsun.shape + (1, )), -earth_v, dsun, invlorentz) cartrep = CartesianRepresentation(x=-dsun * properdir[..., 0] * u.AU, y=-dsun * properdir[..., 1] * u.AU, z=-dsun * properdir[..., 2] * u.AU) return SkyCoord(cartrep, frame=GCRS(obstime=time))
def get_sun(time): """ Determines the location of the sun at a given time (or times, if the input is an array `~astropy.time.Time` object), in geocentric coordinates. Parameters ---------- time : `~astropy.time.Time` The time(s) at which to compute the location of the sun. Returns ------- newsc : `~astropy.coordinates.SkyCoord` The location of the sun as a `~astropy.coordinates.SkyCoord` in the `~astropy.coordinates.GCRS` frame. Notes ----- The algorithm for determining the sun/earth relative position is based on the simplified version of VSOP2000 that is part of ERFA. Compared to JPL's ephemeris, it should be good to about 4 km (in the Sun-Earth vector) from 1900-2100 C.E., 8 km for the 1800-2200 span, and perhaps 250 km over the 1000-3000. """ earth_pv_helio, earth_pv_bary = erfa.epv00(*get_jd12(time, 'tdb')) # We have to manually do aberration because we're outputting directly into # GCRS earth_p = earth_pv_helio['p'] earth_v = earth_pv_bary['v'] # convert barycentric velocity to units of c, but keep as array for passing in to erfa earth_v /= c.to_value(u.au/u.d) dsun = np.sqrt(np.sum(earth_p**2, axis=-1)) invlorentz = (1-np.sum(earth_v**2, axis=-1))**0.5 properdir = erfa.ab(earth_p/dsun.reshape(dsun.shape + (1,)), -earth_v, dsun, invlorentz) cartrep = CartesianRepresentation(x=-dsun*properdir[..., 0] * u.AU, y=-dsun*properdir[..., 1] * u.AU, z=-dsun*properdir[..., 2] * u.AU) return SkyCoord(cartrep, frame=GCRS(obstime=time))
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
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 '{0}' 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("{0}'s position and velocity cannot be " "calculated with the '{1}' 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("{0}'s position cannot be calculated with " "the {1} 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