예제 #1
0
    def __new__(cls,
                value,
                unit=None,
                observer=None,
                target=None,
                radial_velocity=None,
                redshift=None,
                **kwargs):

        obj = super().__new__(cls, value, unit=unit, **kwargs)

        # There are two main modes of operation in this class. Either the
        # observer and target are both defined, in which case the radial
        # velocity and redshift are automatically computed from these, or
        # only one of the observer and target are specified, along with a
        # manually specified radial velocity or redshift. So if a target and
        # observer are both specified, we can't also accept a radial velocity
        # or redshift.
        if target is not None and observer is not None:
            if radial_velocity is not None or redshift is not None:
                raise ValueError(
                    "Cannot specify radial velocity or redshift if both "
                    "target and observer are specified")

        # We only deal with redshifts here and in the redshift property.
        # Otherwise internally we always deal with velocities.
        if redshift is not None:
            if radial_velocity is not None:
                raise ValueError(
                    "Cannot set both a radial velocity and redshift")
            redshift = u.Quantity(redshift)
            # For now, we can't specify redshift=u.one in quantity_input above
            # and have it work with plain floats, but if that is fixed, for
            # example as in https://github.com/astropy/astropy/pull/10232, we
            # can remove the check here and add redshift=u.one to the decorator
            if not redshift.unit.is_equivalent(u.one):
                raise u.UnitsError('redshift should be dimensionless')
            radial_velocity = redshift.to(u.km / u.s, u.doppler_redshift())

        # If we're initializing from an existing SpectralCoord, keep any
        # parameters that aren't being overridden
        if observer is None:
            observer = getattr(value, 'observer', None)
        if target is None:
            target = getattr(value, 'target', None)

        # As mentioned above, we should only specify the radial velocity
        # manually if either or both the observer and target are not
        # specified.
        if observer is None or target is None:
            if radial_velocity is None:
                radial_velocity = getattr(value, 'radial_velocity', None)

        obj._radial_velocity = radial_velocity
        obj._observer = cls._validate_coordinate(observer, label='observer')
        obj._target = cls._validate_coordinate(target, label='target')

        return obj
예제 #2
0
    def redshift(self):
        """
        Redshift of target relative to observer. Calculated from the radial
        velocity.

        Returns
        -------
        `astropy.units.Quantity`
            Redshift of target.
        """
        return self.radial_velocity.to(u.dimensionless_unscaled,
                                       u.doppler_redshift())
예제 #3
0
    def redshift(self):
        """
        Redshift of target relative to observer. Calculated from the radial
        velocity.

        Returns
        -------
        float
            Redshift of target.
        """
        return self.radial_velocity.to(u.dimensionless_unscaled,
                                       u.doppler_redshift()).value
예제 #4
0
def test_doppler_redshift_no_cosmology():
    from astropy.cosmology.units import redshift
    with pytest.raises(u.UnitConversionError, match='not convertible'):
        (0 * (u.km / u.s)).to(redshift, u.doppler_redshift())
예제 #5
0
def test_doppler_redshift(z, rv_ans):
    z_in = z * u.dimensionless_unscaled
    rv_out = z_in.to(u.km / u.s, u.doppler_redshift())
    z_out = rv_out.to(u.dimensionless_unscaled, u.doppler_redshift())
    assert_quantity_allclose(rv_out, rv_ans)
    assert_quantity_allclose(z_out, z_in)  # Check roundtrip
예제 #6
0
    def with_radial_velocity_shift(self,
                                   target_shift=None,
                                   observer_shift=None):
        """
        Apply a velocity shift to this spectral coordinate.

        The shift can be provided as a redshift (float value) or radial
        velocity (`~astropy.units.Quantity` with physical type of 'speed').

        Parameters
        ----------
        target_shift : float or `~astropy.units.Quantity` ['speed']
            Shift value to apply to current target.
        observer_shift : float or `~astropy.units.Quantity` ['speed']
            Shift value to apply to current observer.

        Returns
        -------
        `SpectralCoord`
            New spectral coordinate with the target/observer velocity changed
            to incorporate the shift. This is always a new object even if
            ``target_shift`` and ``observer_shift`` are both `None`.
        """

        if observer_shift is not None and (self.target is None
                                           or self.observer is None):
            raise ValueError("Both an observer and target must be defined "
                             "before applying a velocity shift.")

        for arg in [
                x for x in [target_shift, observer_shift] if x is not None
        ]:
            if isinstance(arg, u.Quantity) and not arg.unit.is_equivalent(
                (u.one, KMS)):
                raise u.UnitsError("Argument must have unit physical type "
                                   "'speed' for radial velocty or "
                                   "'dimensionless' for redshift.")

        # The target or observer value is defined but is not a quantity object,
        #  assume it's a redshift float value and convert to velocity

        if target_shift is None:
            if self._observer is None or self._target is None:
                return self.replicate()
            target_shift = 0 * KMS
        else:
            target_shift = u.Quantity(target_shift)
            if target_shift.unit.physical_type == 'dimensionless':
                target_shift = target_shift.to(u.km / u.s,
                                               u.doppler_redshift())
            if self._observer is None or self._target is None:
                return self.replicate(value=_apply_relativistic_doppler_shift(
                    self, target_shift),
                                      radial_velocity=self.radial_velocity +
                                      target_shift)

        if observer_shift is None:
            observer_shift = 0 * KMS
        else:
            observer_shift = u.Quantity(observer_shift)
            if observer_shift.unit.physical_type == 'dimensionless':
                observer_shift = observer_shift.to(u.km / u.s,
                                                   u.doppler_redshift())

        target_icrs = self._target.transform_to(ICRS())
        observer_icrs = self._observer.transform_to(ICRS())

        pos_hat = SpectralCoord._normalized_position_vector(
            observer_icrs, target_icrs)

        target_velocity = _get_velocities(target_icrs) + target_shift * pos_hat
        observer_velocity = _get_velocities(
            observer_icrs) + observer_shift * pos_hat

        target_velocity = CartesianDifferential(target_velocity.xyz)
        observer_velocity = CartesianDifferential(observer_velocity.xyz)

        new_target = (target_icrs.realize_frame(
            target_icrs.cartesian.with_differentials(
                target_velocity)).transform_to(self._target))

        new_observer = (observer_icrs.realize_frame(
            observer_icrs.cartesian.with_differentials(
                observer_velocity)).transform_to(self._observer))

        init_obs_vel = self._calculate_radial_velocity(observer_icrs,
                                                       target_icrs,
                                                       as_scalar=True)
        fin_obs_vel = self._calculate_radial_velocity(new_observer,
                                                      new_target,
                                                      as_scalar=True)

        new_data = _apply_relativistic_doppler_shift(
            self, fin_obs_vel - init_obs_vel)

        return self.replicate(value=new_data,
                              observer=new_observer,
                              target=new_target)