Example #1
0
    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)
Example #2
0
    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
Example #3
0
    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
Example #6
0
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))
Example #7
0
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))
Example #8
0
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
Example #9
0
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