Source code for gala.coordinates.velocity_transforms

# coding: utf-8

""" Velocity transformations for coordinate representations. """

from __future__ import division, print_function

__author__ = "adrn <adrn@astro.columbia.edu>"

# Standard library

# Third-party
import numpy as np
import astropy.coordinates as coord

__all__ = ['cartesian_to_spherical', 'cartesian_to_physicsspherical',
           'cartesian_to_cylindrical', 'spherical_to_cartesian',
           'physicsspherical_to_cartesian', 'cylindrical_to_cartesian']

def _pos_to_repr(pos):

    if hasattr(pos, 'xyz'):  # Representation-like
        pos_repr = coord.CartesianRepresentation(pos.xyz)

    elif hasattr(pos, 'cartesian') or hasattr(pos, 'to_cartesian'):  # Frame-like
        pos_repr = pos.represent_as(coord.CartesianRepresentation)

    elif hasattr(pos, 'unit'):  # Quantity-like
        pos_repr = coord.CartesianRepresentation(pos)

    else:
        raise TypeError("Unsupported position type '{0}'. Position must be "
                        "an Astropy Representation or Frame, or a "
                        "Quantity instance".format(type(pos)))

    return pos_repr

[docs]def cartesian_to_spherical(pos, vel): r""" Convert a velocity in Cartesian coordinates to velocity components in spherical coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: spherical coordinates consist of a distance, :math:`d`, a longitude, :math:`\phi`, in the range [0, 360] deg, and a latitude, :math:`b`, in the range [-90, 90] deg. The components of the output velocity all have units of velocity, i.e., this is not used for transforming from a cartesian velocity to angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_r\boldsymbol{\hat{d}} + v_\phi\boldsymbol{\hat{\phi}} + v_b\boldsymbol{\hat{b}}\\\\ &= \dot{d}\boldsymbol{\hat{d}} + d\cos b \dot{\phi}\boldsymbol{\hat{\phi}} + d\dot{b}\boldsymbol{\hat{b}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vsph : :class:`~astropy.units.Quantity` Array of spherical velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and spherical car_pos = _pos_to_repr(pos) sph_pos = car_pos.represent_as(coord.SphericalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components d = sph_pos.distance dxy = np.sqrt(car_pos.x**2 + car_pos.y**2) vr = np.sum(car_pos.xyz * vel, axis=0) / d mu_lon = (car_pos.xyz[0]*vel[1] - vel[0]*car_pos.xyz[1]) / dxy**2 vlon = mu_lon * d * np.cos(sph_pos.lat) mu_lat = (car_pos.xyz[2]*(car_pos.xyz[0]*vel[0] + car_pos.xyz[1]*vel[1]) - dxy**2*vel[2]) / d**2 / dxy vlat = -mu_lat * d vsph = np.zeros_like(vel) vsph[0] = vr vsph[1] = vlon vsph[2] = vlat return vsph
[docs]def cartesian_to_physicsspherical(pos, vel): r""" Convert a velocity in Cartesian coordinates to velocity components in spherical coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: physics spherical coordinates consist of a radius, :math:`r`, a longitude, :math:`\phi`, in the range [0, 360] deg and a colatitude, :math:`\theta`, in the range [0, 180] deg, measured from the z-axis. The components of the output velocity all have units of velocity, i.e., this is not used for transforming from a cartesian velocity to angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_r\boldsymbol{\hat{r}} + v_\phi\boldsymbol{\hat{\phi}} + v_\theta\boldsymbol{\hat{\theta}}\\\\ &= \dot{r}\boldsymbol{\hat{r}} + r\sin\theta \dot{\phi}\boldsymbol{\hat{\phi}} + r\dot{\theta}\boldsymbol{\hat{\theta}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vsph : :class:`~astropy.units.Quantity` Array of spherical velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and spherical car_pos = _pos_to_repr(pos) sph_pos = car_pos.represent_as(coord.PhysicsSphericalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components r = sph_pos.r dxy = np.sqrt(car_pos.x**2 + car_pos.y**2) vr = np.sum(car_pos.xyz * vel, axis=0) / r mu_lon = (car_pos.xyz[0]*vel[1] - vel[0]*car_pos.xyz[1]) / dxy**2 vlon = mu_lon * r * np.sin(sph_pos.theta) mu_lat = (car_pos.xyz[2]*(car_pos.xyz[0]*vel[0] + car_pos.xyz[1]*vel[1]) - dxy**2*vel[2]) / r**2 / dxy vlat = mu_lat * r vsph = np.zeros_like(vel) vsph[0] = vr vsph[1] = vlon vsph[2] = vlat return vsph
[docs]def cartesian_to_cylindrical(pos, vel): r""" Convert a velocity in Cartesian coordinates to velocity components in cylindrical coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: cylindrical coordinates consist of a radius, :math:`\rho`, an azimuthal angle, :math:`\phi`, in the range [0, 360] deg, and a z coordinate, :math:`z`. The components of the output velocity all have units of velocity, i.e., this is not used for transforming from a cartesian velocity to angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_\rho\boldsymbol{\hat{\rho}} + v_\phi\boldsymbol{\hat{\phi}} + v_z\boldsymbol{\hat{z}}\\\\ &= \dot{\rho}\boldsymbol{\hat{\rho}} + \rho\dot{\phi}\boldsymbol{\hat{\phi}} + \dot{z}\boldsymbol{\hat{\theta}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vcyl : :class:`~astropy.units.Quantity` Array of spherical velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and spherical car_pos = _pos_to_repr(pos) cyl_pos = car_pos.represent_as(coord.CylindricalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components rho = cyl_pos.rho vrho = np.sum(car_pos.xyz[:2] * vel[:2], axis=0) / rho phidot = (car_pos.xyz[0]*vel[1] - vel[0]*car_pos.xyz[1]) / rho**2 vphi = phidot * rho vcyl = np.zeros_like(vel) vcyl[0] = vrho vcyl[1] = vphi vcyl[2] = vel[2] return vcyl
[docs]def spherical_to_cartesian(pos, vel): r""" Convert a velocity in Spherical coordinates to Cartesian coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: spherical coordinates consist of a distance, :math:`d`, a longitude, :math:`\phi`, in the range [0, 360] deg, and a latitude, :math:`b`, in the range [-90, 90] deg. All components of the input spherical velocity should have units of velocity, i.e., this is not used for transforming angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_r\boldsymbol{\hat{d}} + v_\phi\boldsymbol{\hat{\phi}} + v_b\boldsymbol{\hat{b}}\\\\ &= \dot{d}\boldsymbol{\hat{d}} + d\cos b \dot{\phi}\boldsymbol{\hat{\phi}} + d\dot{b}\boldsymbol{\hat{b}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vxyz : :class:`~astropy.units.Quantity` Array of Cartesian velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and spherical car_pos = _pos_to_repr(pos) sph_pos = car_pos.represent_as(coord.SphericalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components phi = sph_pos.lon lat = sph_pos.lat vr,vlon,vlat = vel vxyz = np.zeros_like(vel) vxyz[0] = vr*np.cos(phi)*np.cos(lat) - np.sin(phi)*vlon - np.cos(phi)*np.sin(lat)*vlat vxyz[1] = vr*np.sin(phi)*np.cos(lat) + np.cos(phi)*vlon - np.sin(phi)*np.sin(lat)*vlat vxyz[2] = vr*np.sin(lat) + np.cos(lat)*vlat return vxyz
[docs]def physicsspherical_to_cartesian(pos, vel): r""" Convert a velocity in Spherical coordinates to Cartesian coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: physics spherical coordinates consist of a radius, :math:`r`, a longitude, :math:`\phi`, in the range [0, 360] deg and a colatitude, :math:`\theta`, in the range [0, 180] deg, measured from the z-axis. The components of the output velocity all have units of velocity, i.e., this is not used for transforming from a cartesian velocity to angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_r\boldsymbol{\hat{r}} + v_\phi\boldsymbol{\hat{\phi}} + v_\theta\boldsymbol{\hat{\theta}}\\\\ &= \dot{r}\boldsymbol{\hat{r}} + r\sin\theta \dot{\phi}\boldsymbol{\hat{\phi}} + r\dot{\theta}\boldsymbol{\hat{\theta}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vxyz : :class:`~astropy.units.Quantity` Array of Cartesian velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and spherical car_pos = _pos_to_repr(pos) sph_pos = car_pos.represent_as(coord.PhysicsSphericalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components phi = sph_pos.phi the = sph_pos.theta vr,vphi,vthe = vel vthe = -vthe vxyz = np.zeros_like(vel) vxyz[0] = vr*np.cos(phi)*np.sin(the) - np.sin(phi)*vphi - np.cos(phi)*np.cos(the)*vthe vxyz[1] = vr*np.sin(phi)*np.sin(the) + np.cos(phi)*vphi - np.sin(phi)*np.cos(the)*vthe vxyz[2] = vr*np.cos(the) + np.sin(the)*vthe return vxyz
[docs]def cylindrical_to_cartesian(pos, vel): r""" Convert a velocity in Spherical coordinates to Cylindrical coordinates. This follows the naming convention used in :mod:`astropy.coordinates`: cylindrical coordinates consist of a radius, :math:`\rho`, an azimuthal angle, :math:`\phi`, in the range [0, 360] deg, and a z coordinate, :math:`z`. The components of the output velocity all have units of velocity, i.e., this is not used for transforming from a cartesian velocity to angular velocities, but rather the velocity vector components in Eq. 2 below. .. math:: \boldsymbol{v} &= v_x\boldsymbol{\hat{x}} + v_y\boldsymbol{\hat{y}} + v_z\boldsymbol{\hat{z}}\\\\ &= v_\rho\boldsymbol{\hat{\rho}} + v_\phi\boldsymbol{\hat{\phi}} + v_z\boldsymbol{\hat{z}}\\\\ &= \dot{\rho}\boldsymbol{\hat{\rho}} + \rho\dot{\phi}\boldsymbol{\hat{\phi}} + \dot{z}\boldsymbol{\hat{\theta}} Parameters ---------- pos : :class:`~astropy.units.Quantity`, :class:`~astropy.coordinates.BaseCoordinateFrame`, :class:`~astropy.coordinates.BaseRepresentation` Input position or positions as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. vel : :class:`~astropy.units.Quantity` Input velocity or velocities as one of the allowed types. You may pass in a :class:`~astropy.units.Quantity` with :class:`~astropy.units.dimensionless_unscaled` units if you are working in natural units. axis=0 is assumed to be the dimensionality axis, e.g., ``vx,vy,vz = vel`` should work. Returns ------- vxyz : :class:`~astropy.units.Quantity` Array of Cartesian velocity components. Will have the same shape as the input velocity. Examples -------- """ # position in Cartesian and cylindrical car_pos = _pos_to_repr(pos) cyl_pos = car_pos.represent_as(coord.CylindricalRepresentation) if not hasattr(vel, 'unit'): raise TypeError("Unsupported velocity type '{}'. Velocity must be " "an Astropy Quantity instance.".format(type(vel))) # get out spherical components phi = cyl_pos.phi vrho,vphi,vz = vel vcyl = np.zeros_like(vel) vcyl[0] = vrho * np.cos(phi) - np.sin(phi) * vphi vcyl[1] = vrho * np.sin(phi) + np.cos(phi) * vphi vcyl[2] = vz return vcyl