Skip to content

Commit 10b59c3

Browse files
Rotation velocity and velocity dispersion additions (#192)
* Lower required precision between cumsum and sum quantities Running on L200m6 crashed for half light radii (difference was 0.13% instead of less than 0.1%) * Implement helper function for mass-weighted rotational velocity * Define azimuthal velocity for subhalo apertures. * Add helper function for cylindrical velocity dispersion vector * Define cylindrical dispersion quantities for aperture properties * Add missing property declaration * Define luminosity-weighted kinematic properties Still need to think of how to handle different angular momentum vectors. * Change calculate_cylindrical_velocities to take reference pos and vel * Define cylindrical velocity calculation on a per-luminosity-band basis * Implementation of luminosity-weighted rotational velocity Testing pending. * Implement luminosity-weighted cylindrical dispersion routines. Tests to be done * Define luminosity weighted kinematics for aperture properties * Add new properties to parameter file * Add new properties to property table * Incorrect function call * Declare properties for bound subhalo * Fix indexing of arrays * Do not recentre star coordinates for cylindrical velocities We do not do so when computing the angular momentum vector, so this change makes it consistent with our choice to not re-centre. * Use stellar centre of mass as reference velocity Including the case for when we do luminosity-weighting. This reflects the same choice we made when computing luminosity-weighted angular momenta. * Use STELLAR CoM velocity as reference, not ALL CoM velocity. * Fix bug: accidental change of velocities within function * Run formatter * Update property table.
1 parent 37bbadd commit 10b59c3

8 files changed

Lines changed: 567 additions & 40 deletions

File tree

SOAP/particle_selection/aperture_properties.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ def MetalFracStar(self):
147147
)
148148
from SOAP.property_calculation.kinematic_properties import (
149149
get_velocity_dispersion_matrix,
150+
get_cylindrical_velocity_dispersion_vector_mass_weighted,
151+
get_cylindrical_velocity_dispersion_vector_luminosity_weighted,
152+
get_rotation_velocity_mass_weighted,
153+
get_rotation_velocity_luminosity_weighted,
150154
get_angular_momentum,
151155
get_angular_momentum_and_kappa_corot_mass_weighted,
152156
get_angular_momentum_and_kappa_corot_luminosity_weighted,
@@ -156,6 +160,9 @@ def MetalFracStar(self):
156160
get_inertia_tensor_mass_weighted,
157161
get_inertia_tensor_luminosity_weighted,
158162
)
163+
from SOAP.property_calculation.cylindrical_coordinates import (
164+
calculate_cylindrical_velocities,
165+
)
159166
from SOAP.core.swift_cells import SWIFTCellGrid
160167
from SOAP.property_calculation.stellar_age_calculator import StellarAgeCalculator
161168
from SOAP.particle_filter.cold_dense_gas_filter import ColdDenseGasFilter
@@ -1448,6 +1455,162 @@ def veldisp_matrix_star(self) -> unyt.unyt_array:
14481455
self.star_mass_fraction, self.vel_star, self.vcom_star
14491456
)
14501457

1458+
@lazy_property
1459+
def star_cylindrical_velocities(self) -> unyt.unyt_array:
1460+
"""
1461+
Calculate the velocities of the star particles in cyclindrical
1462+
coordinates, where the axes are centred on the stellar CoM,
1463+
and the z axis is aligned with the stellar angular momentum.
1464+
"""
1465+
1466+
# We need at least 2 particles to have an angular momentum vector
1467+
if self.Nstar < 2:
1468+
return None
1469+
1470+
# This can happen if we have particles on top of each other
1471+
# or with the same velocity
1472+
if np.sum(self.Lstar) == 0:
1473+
return None
1474+
1475+
# Get velocities in cylindrical coordinates
1476+
return calculate_cylindrical_velocities(
1477+
self.pos_star,
1478+
self.vel_star,
1479+
self.Lstar,
1480+
reference_velocity=self.vcom_star,
1481+
)
1482+
1483+
@lazy_property
1484+
def StellarRotationalVelocity(self) -> unyt.unyt_array:
1485+
"""
1486+
Mass-weighted average azimuthal velocity of stars.
1487+
"""
1488+
if (self.Nstar < 2) or (np.sum(self.Lstar) == 0):
1489+
return None
1490+
return get_rotation_velocity_mass_weighted(
1491+
self.mass_star, self.star_cylindrical_velocities[:, 1]
1492+
)
1493+
1494+
@lazy_property
1495+
def StellarCylindricalVelocityDispersionVector(self) -> unyt.unyt_array:
1496+
if (self.Nstar < 2) or (np.sum(self.Lstar) == 0):
1497+
return None
1498+
return get_cylindrical_velocity_dispersion_vector_mass_weighted(
1499+
self.mass_star, self.star_cylindrical_velocities
1500+
)
1501+
1502+
@lazy_property
1503+
def StellarCylindricalVelocityDispersion(self) -> unyt.unyt_array:
1504+
if self.StellarCylindricalVelocityDispersionVector is None:
1505+
return None
1506+
return np.sqrt((self.StellarCylindricalVelocityDispersionVector**2).sum() / 3)
1507+
1508+
@lazy_property
1509+
def StellarCylindricalVelocityDispersionVertical(self) -> unyt.unyt_array:
1510+
if self.StellarCylindricalVelocityDispersionVector is None:
1511+
return None
1512+
return self.StellarCylindricalVelocityDispersionVector[2]
1513+
1514+
@lazy_property
1515+
def StellarCylindricalVelocityDispersionDiscPlane(self) -> unyt.unyt_array:
1516+
if self.StellarCylindricalVelocityDispersionVector is None:
1517+
return None
1518+
return np.sqrt((self.StellarCylindricalVelocityDispersionVector[:2] ** 2).sum())
1519+
1520+
@lazy_property
1521+
def star_cylindrical_velocities_luminosity_weighted(self) -> unyt.unyt_array:
1522+
"""
1523+
Calculate the velocities of the star particles in cylindrical
1524+
coordinates, where the origin and reference frame are centred on the
1525+
stellar centre of light in each band. The z axis is aligned with the
1526+
stellar angular momentum obtained from each band.
1527+
"""
1528+
1529+
# We need at least 2 particles to have an angular momentum vector
1530+
if self.Nstar < 2:
1531+
return None
1532+
1533+
# This can happen if we have particles on top of each other
1534+
# or with the same velocity
1535+
if np.sum(self.Lstar_luminosity_weighted) == 0:
1536+
return None
1537+
1538+
# We iterate over bands to use their own reference vector and luminosity-
1539+
# weighted centre of mass phase space coordinates.
1540+
cylindrical_velocities = (
1541+
np.zeros(
1542+
(
1543+
self.stellar_luminosities.shape[1],
1544+
self.stellar_luminosities.shape[0],
1545+
3,
1546+
)
1547+
)
1548+
* self.vel_star.units
1549+
)
1550+
for i_band, particle_luminosities_i_band in enumerate(
1551+
self.stellar_luminosities.T
1552+
):
1553+
cylindrical_velocities[i_band] = calculate_cylindrical_velocities(
1554+
self.pos_star,
1555+
self.vel_star,
1556+
self.Lstar_luminosity_weighted[i_band * 3 : (1 + i_band) * 3],
1557+
reference_velocity=self.vcom_star,
1558+
)
1559+
1560+
return cylindrical_velocities
1561+
1562+
@lazy_property
1563+
def StellarRotationalVelocityLuminosityWeighted(self) -> unyt.unyt_array:
1564+
if (self.Nstar < 2) or (np.sum(self.Lstar) == 0):
1565+
return None
1566+
return get_rotation_velocity_luminosity_weighted(
1567+
self.stellar_luminosities,
1568+
self.star_cylindrical_velocities_luminosity_weighted[:, :, 1],
1569+
)
1570+
1571+
@lazy_property
1572+
def StellarCylindricalVelocityDispersionVectorLuminosityWeighted(
1573+
self,
1574+
) -> unyt.unyt_array:
1575+
if (self.Nstar < 2) or (np.sum(self.Lstar) == 0):
1576+
return None
1577+
return get_cylindrical_velocity_dispersion_vector_luminosity_weighted(
1578+
self.stellar_luminosities,
1579+
self.star_cylindrical_velocities_luminosity_weighted,
1580+
)
1581+
1582+
@lazy_property
1583+
def StellarCylindricalVelocityDispersionLuminosityWeighted(self) -> unyt.unyt_array:
1584+
if self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted is None:
1585+
return None
1586+
return np.sqrt(
1587+
(
1588+
self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted**2
1589+
).sum(axis=1)
1590+
/ 3
1591+
)
1592+
1593+
@lazy_property
1594+
def StellarCylindricalVelocityDispersionVerticalLuminosityWeighted(
1595+
self,
1596+
) -> unyt.unyt_array:
1597+
if self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted is None:
1598+
return None
1599+
return self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted[:, 2]
1600+
1601+
@lazy_property
1602+
def StellarCylindricalVelocityDispersionDiscPlaneLuminosityWeighted(
1603+
self,
1604+
) -> unyt.unyt_array:
1605+
if self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted is None:
1606+
return None
1607+
return np.sqrt(
1608+
(
1609+
self.StellarCylindricalVelocityDispersionVectorLuminosityWeighted[:, :2]
1610+
** 2
1611+
).sum(axis=1)
1612+
)
1613+
14511614
@lazy_property
14521615
def KineticEnergyStars(self) -> unyt.unyt_quantity:
14531616
"""
@@ -3583,6 +3746,14 @@ class ApertureProperties(HaloProperty):
35833746
"veldisp_matrix_gas": False,
35843747
"veldisp_matrix_dm": False,
35853748
"veldisp_matrix_star": False,
3749+
"StellarRotationalVelocity": False,
3750+
"StellarCylindricalVelocityDispersion": False,
3751+
"StellarCylindricalVelocityDispersionVertical": False,
3752+
"StellarCylindricalVelocityDispersionDiscPlane": False,
3753+
"StellarRotationalVelocityLuminosityWeighted": False,
3754+
"StellarCylindricalVelocityDispersionLuminosityWeighted": False,
3755+
"StellarCylindricalVelocityDispersionVerticalLuminosityWeighted": False,
3756+
"StellarCylindricalVelocityDispersionDiscPlaneLuminosityWeighted": False,
35863757
"KineticEnergyGas": False,
35873758
"KineticEnergyStars": False,
35883759
"Mgas_SF": False,

0 commit comments

Comments
 (0)