"""
Default registration functions.
If you add one, don't forget to add it to global_registration_functions
at the end of the file.
"""
import unyt
from typing import Union
from velociraptor.exceptions import RegistrationDoesNotMatchError
from velociraptor.units import VelociraptorUnits
from velociraptor.regex import cached_regex
from velociraptor.catalogue.translator import (
get_aperture_unit,
get_particle_property_name_conversion,
)
[docs]def registration_fail_all(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Basic registration function showing function signature that is
required and automatically fails all tests against itself.
Function signature:
+ field_path: the name of the field
+ unit_system: a VelociraptorUnits instance that contains all unit
information that is available from the velociraptor catalogue
Return signature:
+ field_units: the units that correspond to field_path.
+ name: A fancy (possibly LaTeX'd) name for the field.
+ snake_case: A correct snake_case name for the field.
"""
if field_path == "ThisFieldPathWouldNeverExist":
return (
unit_system.length,
"Fancy $N_{\\rm ever}$ exists",
"this_field_path_would_never_exist",
)
else:
raise RegistrationDoesNotMatchError
[docs]def registration_apertures(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers aperture values by searching them with regex.
"""
# Capture group 1: quantity
# Capture group 2: particle type
# Capture group 3: sf / nsf
# Capture group 4: size of aperture
match_string = "Aperture_([^_]*)_([a-zA-Z]*)?_?([a-zA-Z]*)?_?([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
quantity = match.group(1)
ptype = match.group(2)
star_forming = match.group(3)
aperture_size = int(match.group(4))
unit = get_aperture_unit(quantity, unit_system)
name = get_particle_property_name_conversion(quantity, ptype)
if star_forming:
sf_in_name = f"{star_forming.upper()} "
else:
sf_in_name = ""
full_name = f"{sf_in_name}{name} ({aperture_size} kpc)"
snake_case = field_path.lower().replace("aperture_", "")
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_projected_apertures(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers aperture values by searching them with regex.
"""
# Capture group 1: aperture number
# Capture group 2: quantity
# Capture group 3: particle type
# Capture group 4: sf / nsf
# Capture group 5: size of aperture
match_string = (
"Projected_aperture_([0-9])_([^_]*)_([a-zA-Z]*)?_?([a-zA-Z]*)?_?([0-9]*)_kpc"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
aperture = match.group(1)
quantity = match.group(2)
ptype = match.group(3)
star_forming = match.group(4)
aperture_size = int(match.group(5))
unit = get_aperture_unit(quantity, unit_system)
name = get_particle_property_name_conversion(quantity, ptype)
if star_forming:
sf_in_name = f"{star_forming.upper()} "
else:
sf_in_name = ""
full_name = f"{sf_in_name}{name} (Proj. {aperture}, {aperture_size} kpc)"
snake_case = field_path.lower().replace("aperture_", "")
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_energies(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers all energy related quantities (those beginning with E).
"""
if not field_path[:2] in ["Ef", "Ek", "Ep", "En"]:
raise RegistrationDoesNotMatchError
if field_path[:5] == "Efrac":
# This is an energy _fraction_
full_name = "Energy Fraction"
unit = unyt.dimensionless
else:
# This is an absolute energy
if field_path[:4] == "Ekin":
full_name = "Kinetic Energy"
elif field_path[:4] == "Epot":
full_name = "Potential Energy"
else:
full_name = "Energy"
unit = unit_system.mass * unit_system.velocity * unit_system.velocity
return unit, full_name, field_path.lower()
[docs]def registration_ids(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers all quantities related to particle ids and halo ids (those beginning or ending with ID).
"""
if not (field_path[:2] == "ID" or field_path[-2:] == "ID"):
raise RegistrationDoesNotMatchError
# As identifiers, all of these quantities are dimensionless
unit = unyt.dimensionless
if field_path == "ID":
full_name = "Halo ID"
elif field_path == "ID_mpb":
full_name = "ID of Most Bound Particle"
elif field_path == "ID_minpot":
full_name = "ID of Particle at Potential Minimum"
elif field_path == "hostHaloID":
full_name = "Host Halo ID"
else:
full_name = "Generic ID"
return unit, full_name, field_path.lower()
[docs]def registration_rotational_support(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers rotational support quantities (those beginning with K).
Note that this corresponds to \\kappa in Sales+2010 _not_ K.
"""
if not field_path[0] == "K":
raise RegistrationDoesNotMatchError
# All quantities are ratios and so are dimensionless
unit = unyt.dimensionless
# Capture group 1: particle type
# Capture group 2: star forming / not star forming
match_string = "Krot_?([a-z]*)_?([a-z]*)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
ptype = match.group(1)
star_forming = match.group(2)
full_name = "$\\kappa_{{\\rm rot}"
if ptype:
full_name += f", {{\\rm {ptype}}}"
full_name += "}$"
if star_forming:
full_name += f" ({star_forming.upper()})"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_angular_momentum(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers values starting with L, those that represent
angular momenta.
"""
if not field_path[0] == "L":
raise RegistrationDoesNotMatchError
# All are angular momenta, so have same units.
unit = unit_system.mass * unit_system.length * unit_system.velocity
# Capture group 1: axis (x, y, z)
# Capture group 2: radius within this was calculated, e.g. 200crit
# Capture group 3: excluding or not excluding
# Capture group 4: particle type
# Capture group 5: star forming?
match_string = "L([a-z])_?([A-Z]*[0-9]+[a-z]*)?_?(excl)?_?([a-z]*)_?([a-z]*)"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
axis = match.group(1)
radius = match.group(2)
excluding = match.group(3)
ptype = match.group(4)
star_forming = match.group(5)
full_name = "$L_{"
if axis:
full_name += axis
if radius:
full_name += f", {{\\rm {radius}}}"
full_name += "}$"
if ptype:
full_name += " ("
if excluding:
full_name += "Excl. "
cap_ptype = ptype[0].upper() + ptype[1:]
full_name += cap_ptype
if star_forming:
full_name += f", {star_forming.upper()}"
full_name += ")"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registration for all mass-based quantities. (Start with M)
"""
if not field_path[0] == "M":
raise RegistrationDoesNotMatchError
# All, obviously, have a unit of mass
unit = unit_system.mass
full_name = ""
# Deal with special cases.
if field_path == "Mvir":
full_name = "$M_{\\rm vir}$"
elif field_path == "Mass_FOF":
full_name = "$M_{\\rm FOF}$"
elif field_path == "Mass_tot":
full_name = r"$M$"
elif field_path == "Mass_interloper":
full_name = "$M_{\\rm BG}$"
# General regex matching case.
# Capture group 1: Mass or M
# Capture group 2: radius within this was calculated, e.g. 200crit
# Capture group 3: excluding?
# Capture group 4: ptype
# Capture group 5: star forming?
# Capture group 6: "other"
match_string = (
"(Mass|M)_?([A-Z]*[0-9]+[a-z]*)?_?(excl)?_?([a-z]*)_?(nsf|sf)?_?([a-zA-Z0-9]*)"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
if match and not full_name:
mass = match.group(1)
radius = match.group(2)
excluding = match.group(3)
ptype = match.group(4)
star_forming = match.group(5)
other = match.group(6)
full_name = "$M"
if radius:
full_name += f"_{{\\rm {radius}}}"
elif other:
full_name += f"_{{\\rm {other}}}"
full_name += "$"
if ptype:
full_name += " ("
if excluding:
full_name += "Excl. "
cap_ptype = ptype[0].upper() + ptype[1:]
full_name += cap_ptype
if star_forming:
full_name += f", {star_forming.upper()}"
full_name += ")"
return unit, full_name, field_path.lower()
[docs]def registration_rvmax_quantities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registration for all quantities measured within RVmax (Start with RVmax)
"""
if not field_path[:5] == "RVmax":
raise RegistrationDoesNotMatchError
# Capture group 1: Eigenvector or velocity dispersion
# Capture group 2: xx, xy, etc. for above
# Capture group 3: Angular momentum quantity
# Capture group 4: x, y, z for angular momentum
# Capture group 5: catch all others
match_string = "RVmax_((eig|veldisp)_([a-z]{2}))?_?(L([a-z]))?_?([a-zA-Z0-9_]*)"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
raise RegistrationDoesNotMatchError
return # TODO
[docs]def registration_radii(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registration for all radii quantities (start with R_)
"""
# First, two special cases.
if field_path == "Rvir":
full_name = "$R_{\\rm vir}$"
elif field_path == "Rmax":
full_name = "$R_{\\rm max}$"
elif field_path[:2] != "R_":
raise RegistrationDoesNotMatchError
unit = unit_system.length
# Capture group 1: Characteristic scale
# Capture group 2: Excluding?
# Capture group 3: particle type
# Capture group 4: star forming?
match_string = "R_([a-zA-Z0-9]*)_?(excl)?_?([a-z]*)?_?(sf|nsf)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
radius = match.group(1)
excluding = match.group(2)
ptype = match.group(3)
star_forming = match.group(4)
full_name = "$R"
if radius:
full_name += f"_{{\\rm {radius}}}"
full_name += "$"
if ptype:
full_name += " ("
if excluding:
full_name += "Excl. "
cap_ptype = ptype[0].upper() + ptype[1:]
full_name += cap_ptype
if star_forming:
full_name += f", {star_forming.upper()}"
full_name += ")"
return unit, full_name, field_path.lower()
[docs]def registration_temperature(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers temperature based quantites (Those beginning with T).
"""
if not field_path[0] == "T":
raise RegistrationDoesNotMatchError
unit = unyt.K
# Capture group 1: particle type
# Capture group 2: star forming?
match_string = "T_?([a-z]*)?_?(sf|nsf)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
ptype = match.group(1)
star_forming = match.group(2)
full_name = "$T$"
if ptype:
full_name += " ("
cap_ptype = ptype[0].upper() + ptype[1:]
full_name += cap_ptype
if star_forming:
full_name += f", {star_forming.upper()}"
full_name += ")"
return unit, full_name, field_path.lower()
[docs]def registration_structure_type(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the StructureType field.
"""
if not field_path == "Structuretype":
raise RegistrationDoesNotMatchError
return unyt.dimensionless, "Structure Type", field_path.lower()
[docs]def registration_velocities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers velocity quantities (those starting with V).
"""
if not field_path[0] == "V":
raise RegistrationDoesNotMatchError
unit = unit_system.velocity
if field_path == "Vmax":
# Special case, handle here
full_name = "$V_{\\rm max}$"
else:
# Need to do a regex search
# Capture group 1: X, Y, Z
# Capture group 2: mbp or minpot? Could be empty.
# Capture group 4: gas/star.
match_string = "V(X|Y|Z)c([a-z]*)?(_([a-z]*))?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
coordinate = match.group(1)
ptype = match.group(4)
misc = match.group(2)
full_name = f"$V_{coordinate.lower()}$"
if ptype:
full_name += f" ({ptype})"
if misc:
if misc == "mbp":
full_name = f"Most bound particle {full_name}"
elif misc == "minpot":
full_name = f"Minimum potential {full_name}"
else:
full_name = f"{misc} {full_name}"
else:
full_name = "CoM " + full_name
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_positions(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers all positon based quantities (those beginning with X, Y, or Z).
"""
if not field_path[0] in ["X", "Y", "Z"] and not field_path[:4] == "Zmet":
raise RegistrationDoesNotMatchError
# All position quantities have units of length
unit = unit_system.length
# Capture group 1: x, y, or z
# Capture group 2: ignore
# Capture group 3: ptype
# Capture group 4: misc info, e.g. mbp or minpot
match_string = "(X|Y|Z)c(_([a-z]*))?([a-z]*)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
coordinate = match.group(1)
ptype = match.group(3)
misc = match.group(4)
full_name = f"${coordinate.lower()}$"
if ptype:
full_name += f" ({ptype})"
if misc:
if misc == "mbp":
full_name = f"Most bound particle {full_name}"
elif misc == "minpot":
full_name = f"Minimum potential {full_name}"
else:
full_name = f"{misc} {full_name}"
else:
full_name = "CoM " + full_name
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_concentration(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers concentration values (those beginning with c).
"""
if not field_path == "cNFW":
raise RegistrationDoesNotMatchError
return unyt.dimensionless, "Concentration $c_{\\rm NFW}$", field_path.lower()
[docs]def registration_eigenvectors(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers eigenvector quantities (those beginning with eig).
"""
if not field_path[:3] == "eig":
raise RegistrationDoesNotMatchError
unit = unit_system.length
# Need to do a regex search
# Capture group 1: xy, etc.
# Capture group 2: gas/star.
match_string = "eig_([a-z][a-z])_?([a-z]*)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
coordinate = match.group(1)
ptype = match.group(2)
full_name = f"$\\hat{{r}}_{{{{\\rm v}}, {coordinate.lower()}}}$"
if ptype:
full_name += f" ({ptype})"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_veldisp(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers velocity dispersion quantities (those beginning with veldisp).
"""
if not field_path[:7] == "veldisp":
raise RegistrationDoesNotMatchError
unit = unit_system.velocity
# Need to do a regex search
# Capture group 1: xy, etc.
# Capture group 2: gas/star.
match_string = "veldisp_([a-z][a-z])_?([a-z]*)?"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
coordinate = match.group(1)
ptype = match.group(2)
full_name = f"$\\sigma_{{{{\\rm v}}, {coordinate.lower()}}}$"
if ptype:
full_name += f" ({ptype})"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, field_path.lower()
[docs]def registration_stellar_age(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the stellar ages properties (currently tage_star).
"""
if field_path == "tage_star":
return unit_system.age, "Mean Stellar Age", field_path.lower()
else:
raise RegistrationDoesNotMatchError
[docs]def registration_element_mass_fractions(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the element mass fraction properties.
Hopefully this is changed in the future as this is a mess.
"""
if not field_path[:20] == "ElementMassFractions":
raise RegistrationDoesNotMatchError
unit = unit_system.metallicity
# Need to do a regex search
# Capture group 1,2: index number - if not present default to 0
# Capture group 3: mass weighted?
# Capture group 4: units
# Capture group 5: particle typr
match_string = (
"ElementMassFractions(_index_)?([0-9]*)_([a-zA-Z]+)_([a-zA-Z]+)_?([a-z]*)"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
snake_case = "element"
if match:
index = match.group(2) if match.group(2) else 0
mass_weighted = match.group(3)
extracted_units = match.group(4)
ptype = match.group(5)
full_name = f"Element {index} Mass Fraction"
snake_case = f"{snake_case}_{index}"
if ptype:
cap_ptype = ptype[0].upper() + ptype[1:]
full_name = f"{cap_ptype} {full_name}"
snake_case += f"_{ptype}"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, snake_case
[docs]def registration_dust_mass_fractions(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the dust mass fraction properties.
Hopefully this is changed in the future as this is a mess.
"""
if not field_path[:17] == "DustMassFractions":
raise RegistrationDoesNotMatchError
unit = unit_system.metallicity
# Need to do a regex search
# Capture group 1,2: index number - if not present default to 0
# Capture group 3: mass weighted?
# Capture group 4: units
# Capture group 5: particle typr
match_string = (
"DustMassFractions(_index_)?([0-9]*)_([a-zA-Z]+)_([a-zA-Z]+)_?([a-z]*)"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
snake_case = "dust"
if match:
index = match.group(2) if match.group(2) else 0
mass_weighted = match.group(3)
extracted_units = match.group(4)
ptype = match.group(5)
full_name = f"Dust {index} Mass Fraction"
snake_case = f"{snake_case}_{index}"
if ptype:
cap_ptype = ptype[0].upper() + ptype[1:]
full_name = f"{cap_ptype} {full_name}"
snake_case += f"_{ptype}"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, snake_case
[docs]def registration_number(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the number of particles in each halo (n_{bh, gas, star} and npart).
"""
if field_path[:2] == "n_":
unit = unyt.dimensionless
switch = {
"bh": "Black Hole",
"gas": "Gas",
"star": "Star",
"interloper": "Interloper",
}
snake_case = field_path[2:]
full_name = f"Number of {switch.get(snake_case, 'Unknown')} Particles"
elif field_path == "npart":
unit = unyt.dimensionless
full_name = "Number of Particles"
snake_case = "part"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, snake_case
[docs]def registration_gas_H_and_He_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the masses in Hydrogen & Helium within apertures
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_([a-zA-Z]*)_aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
long_species = match.group(1)
aperture_size = match.group(2)
try:
short_species = {"HeliumMasses": "He", "HydrogenMasses": "H"}[long_species]
long_name_species = {
"HeliumMasses": "Helium",
"HydrogenMasses": "Hydrogen",
}[long_species]
math_name = {"HeliumMasses": "M_{\\rm He}", "HydrogenMasses": "M_{\\rm H}"}[
long_species
]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = f"{long_name_species} Gas Mass {math_name} ({aperture_size} kpc)"
snake_case = f"{short_species}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_gas_diffuse_element_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the masses in Hydrogen & Helium within apertures
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_Diffuse([a-zA-Z]*)MassesFrom(Table|Model)_aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
element = match.group(1)
table_model = match.group(2)
aperture_size = match.group(3)
try:
long_name_element = (
f"Diffuse {element} from depletion {table_model.lower()}"
)
element_symbol = {
"Carbon": "C",
"Oxygen": "O",
"Magnesium": "Mg",
"Silicon": "Si",
"Iron": "Fe",
}[element]
math_name = (
f"M^{{\\rm {table_model.lower()}}}_{{\\rm {element_symbol}, diffuse}}"
)
except KeyError:
raise RegistrationDoesNotMatchError
full_name = (
f"{element} ({table_model}) Gas Mass {element_symbol} ({aperture_size} kpc)"
)
snake_case = f"{element.lower()}_mass_{table_model.lower()}_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_dust_masses_from_table(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the dust mass fraction properties.
"""
if not field_path[:28] == "Aperture_DustMassesFromTable":
raise RegistrationDoesNotMatchError
unit = unit_system.mass
match_string = "Aperture_DustMassesFromTable_aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
aperture_size = match.group(1)
full_name = f"Total Dust Mass from Tables ({aperture_size} kpc)"
snake_case = f"dust_mass_table_{aperture_size}_kpc"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, snake_case
[docs]def registration_gas_hydrogen_species_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the masses in hydrogen species within apertures.
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_([a-zA-Z]*)_(index_0_)?aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
long_species = match.group(1)
aperture_size = match.group(3)
try:
short_species = {
"AtomicHydrogenMasses": "HI",
"IonisedHydrogenMasses": "HII",
"MolecularHydrogenMasses": "H2",
}[long_species]
full_name_species = {
"AtomicHydrogenMasses": "HI",
"IonisedHydrogenMasses": "HII",
"MolecularHydrogenMasses": "H$_2$",
}[long_species]
math_name_species = {
"AtomicHydrogenMasses": "$M_{\\rm HI}$",
"IonisedHydrogenMasses": "$M_{\\rm HII}$",
"MolecularHydrogenMasses": "$M_{\\rm H_2}$",
}[long_species]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = (
f"{full_name_species} Gas Mass {math_name_species} ({aperture_size} kpc)"
)
snake_case = f"{short_species}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_cold_dense_gas_properties(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the mass of cold (T < 10^4.5 K), dense (nH > 0.1 cm^-3) gas in apertures.
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_ColdDense([a-zA-Z]*)Masses_aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
quantity_key = match.group(1)
aperture_size = match.group(2)
try:
long_quantity = {"DiffuseMetal": "Diffuse Metal", "Gas": "Gas"}[
quantity_key
]
short_quantity = {"DiffuseMetal": "diffuse_metal", "Gas": "gas"}[
quantity_key
]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = (
f"{long_quantity} Masses in Cold, Dense ($T < 10^{{4.5}} [{{\\rm K}}]$, "
f"$n_{{\\rm H}}$ > 0.1 [{{\\rm cm^{{-3}}}}]$) Gas ({aperture_size} kpc)"
)
snake_case = f"cold_dense_{short_quantity}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_log_element_ratios_times_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the log10(Fe/H) times mass and log10(O/H) times mass within apertures for two particle floor values
"""
unit = unit_system.mass
# Capture aperture size
match_string = (
"Aperture_([a-zA-Z]*)Masses(Lo|Hi)Floor_aperture_total_([a-zA-Z]*)_([0-9]*)_kpc"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
long_species = match.group(1)
floor_type = match.group(2)
part_type = match.group(3)
aperture_size = match.group(4)
try:
short_species = {
"LogOxygenOverHydrogen": "O_over_H",
"LogIronOverHydrogen": "Fe_over_H",
"LogOxygenOverHydrogenAtomic": "O_over_H_atomic",
"LogOxygenOverHydrogenMolecular": "O_over_H_molecular",
}[long_species]
element_name = {
"LogOxygenOverHydrogen": "Oxygen",
"LogIronOverHydrogen": "Iron",
"LogOxygenOverHydrogenAtomic": "Atomic-phase Oxygen",
"LogOxygenOverHydrogenMolecular": "Molecular-phase Oxygen",
}[long_species]
fraction_name = {
"LogOxygenOverHydrogen": "O/H",
"LogIronOverHydrogen": "Fe/H",
"LogOxygenOverHydrogenAtomic": "O/H",
"LogOxygenOverHydrogenMolecular": "O/H",
}[long_species]
short_floortype = {"Lo": "lowfloor", "Hi": "highfloor"}[floor_type]
floor_value = {"Lo": "-4", "Hi": "-3"}[floor_type]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = (
f"Log10 {element_name} Abundance Weighted {part_type.capitalize()} Mass ({fraction_name}) "
f"$\times M_{{\\rm gas}}$, from particle values floored at [{fraction_name}]$\\gtreq {floor_value}$ "
f"({aperture_size} kpc)"
)
snake_case = f"log_{short_species}_times_{part_type}_mass_{short_floortype}_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_lin_element_ratios_times_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the Fe/H times mass and O/H times mass within apertures for two particle floor values
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_([a-zA-Z]*)Masses_aperture_total_([a-zA-Z]*)_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
long_species = match.group(1)
part_type = match.group(2)
aperture_size = match.group(3)
try:
short_species = {
"TotalOxygenOverHydrogen": "O_over_H_total",
"OxygenOverHydrogen": "O_over_H",
"IronOverHydrogen": "Fe_over_H",
"IronfromSNIaOverHydrogen": "FeSNIa_over_H",
}[long_species]
element_name = {
"TotalOxygenOverHydrogen": "Oxygen",
"OxygenOverHydrogen": "Oxygen",
"IronOverHydrogen": "Iron",
"IronfromSNIaOverHydrogen": "SNIaIron",
}[long_species]
fraction_name = {
"TotalOxygenOverHydrogen": "O/H",
"OxygenOverHydrogen": "O/H",
"IronOverHydrogen": "Fe/H",
"IronfromSNIaOverHydrogen": "Fe(SNIa)/H",
}[long_species]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = (
f"Linear {element_name} Abundance Weighted {part_type.capitalize()} Mass ({fraction_name}) "
f"$\times M_{{\\rm gas}}$ ({aperture_size} kpc)"
)
snake_case = f"lin_{short_species}_times_{part_type}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_dust_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the masses in dust within apertures
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_([a-zA-Z]*)_aperture_total_gas_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
long_species = match.group(1)
aperture_size = match.group(2)
try:
short_species = {
"GraphiteMasses": "graphite",
"SilicatesMasses": "silicates",
"SmallGrainMasses": "small_grain",
"LargeGrainMasses": "large_grain",
"GraphiteMassesAtomic": "atomic_graphite",
"SilicatesMassesAtomic": "atomic_silicates",
"SmallGrainMassesAtomic": "atomic_small_grain",
"LargeGrainMassesAtomic": "atomic_large_grain",
"GraphiteMassesMolecular": "molecular_graphite",
"SilicatesMassesMolecular": "molecular_silicates",
"SmallGrainMassesMolecular": "molecular_small_grain",
"LargeGrainMassesMolecular": "molecular_large_grain",
"GraphiteMassesColdDense": "cold_dense_graphite",
"SilicatesMassesColdDense": "cold_dense_silicates",
"SmallGrainMassesColdDense": "cold_dense_small_grain",
"LargeGrainMassesColdDense": "cold_dense_large_grain",
}[long_species]
pretty_name = {
"GraphiteMasses": "Graphite Dust Mass",
"SilicatesMasses": "Silicate Dust Mass",
"SmallGrainMasses": "small_grain",
"LargeGrainMasses": "large_grain",
"GraphiteMassesAtomic": "Graphite Dust Mass in Atomic Gas",
"SilicatesMassesAtomic": "Silicate Dust Mass in Atomic Gas",
"SmallGrainMassesAtomic": "atomic_small_grain",
"LargeGrainMassesAtomic": "atomic_large_grain",
"GraphiteMassesMolecular": "Graphite Dust Mass in Molecular Gas",
"SilicatesMassesMolecular": "Silicate Dust Mass in Molecular Gas",
"SmallGrainMassesMolecular": "molecular_small_grain",
"LargeGrainMassesMolecular": "molecular_large_grain",
"GraphiteMassesColdDense": "Graphite Dust Mass in Cold-Dense Gas",
"SilicatesMassesColdDense": "Silicate Dust Mass in Cold-Dense Gas",
"SmallGrainMassesColdDense": "cold_dense_small_grain",
"LargeGrainMassesColdDense": "cold_dense_large_grain",
}[long_species]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = f"{pretty_name} ({aperture_size} kpc)"
snake_case = f"{short_species}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_stellar_luminosities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the luminosities within apertures
"""
unit = unyt.dimensionless
# Capture aperture size
match_string = (
"Aperture_Luminosities_index_([0-9]?)_aperture_total_star_([0-9]*)_kpc"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
bands = ["u", "g", "r", "i", "z", "Y", "J", "H", "K"]
band = bands[int(match.group(1))]
aperture_size = match.group(2)
full_name = f"{band}-Band Luminosity ({aperture_size} kpc)"
snake_case = f"{band}_luminosity_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_hydrogen_phase_fractions(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the phase fractions for hydrogen.
"""
if field_path[:8] != "Hydrogen":
raise RegistrationDoesNotMatchError
unit = unyt.dimensionless
# Need to do a regex search
# Capture group 1: ionized
# Capture group 2: massweighted
# Capture group 3: units
# Capture group 4: particle type
match_string = "Hydrogen([a-zA-Z]+)Fractions_([a-zA-Z]+)_([a-zA-Z]+)_?([a-z]*)"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
ionized = match.group(1)
mass_weighted = match.group(2)
extracted_units = match.group(3)
ptype = match.group(4)
full_name = f"Hydrogen {ionized} Fraction"
snake_case = ionized.lower()
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_black_hole_masses(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Sub-grid black hole property registrations.
"""
if not field_path[:13] == "SubgridMasses" and field_path[-2:] == "bh":
raise RegistrationDoesNotMatchError
unit = unit_system.mass
# Need to do a regex search
# Capture group 1: average, min, max.
# Capture group 2: optional _solar_mass part - backwards compat.
match_string = "SubgridMasses_([a-z]+)(_solar_mass|)_bh"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
minmax = match.group(1)
full_name = f"Subgrid Black Hole Mass ({minmax})"
snake_case = minmax.lower()
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
return
[docs]def registration_stellar_birth_densities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Stellar birth density registrations.
"""
if not field_path[:14] == "BirthDensities" and field_path[-4:] == "star":
raise RegistrationDoesNotMatchError
unit = unit_system.mass / unit_system.length ** 3
# Need to do a regex search (average, min, max)
match_string = "BirthDensities_([a-z]+)_star"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
minmax = match.group(1)
full_name = f"Stellar Birth Density ({minmax})"
snake_case = minmax.lower()
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
return
[docs]def registration_snii_thermal_feedback_densities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
SNII thermal feedback density registrations.
"""
if (
not field_path[:14] == "DensitiesAtLastSupernovaEvent"
and field_path[-4:] == "gas"
):
raise RegistrationDoesNotMatchError
unit = unit_system.mass / unit_system.length ** 3
# Need to do a regex search (average, min, max)
match_string = "DensitiesAtLastSupernovaEvent_([a-z]+)_gas"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
minmax = match.group(1)
full_name = f"SNII Thermal Feedback Density ({minmax})"
snake_case = minmax.lower()
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
return
[docs]def registration_species_fractions(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the species mass fraction properties.
Hopefully this is changed in the future as this is a mess.
"""
if not field_path[:16] == "SpeciesFractions":
raise RegistrationDoesNotMatchError
unit = unyt.dimensionless
# Need to do a regex search
# Capture group 1,2: index number - if not present default to 0
# Capture group 3: mass weighted?
# Capture group 4: units
# Capture group 5: particle type
match_string = (
"SpeciesFractions(_index_)?([0-9]*)_([a-zA-Z]+)_([a-zA-Z]+)_?([a-z]*)"
)
regex = cached_regex(match_string)
match = regex.match(field_path)
snake_case = "species"
if match:
index = match.group(2) if match.group(2) else 0
mass_weighted = match.group(3)
extracted_units = match.group(4)
ptype = match.group(5)
full_name = f"Species {index} Fraction"
snake_case = f"{snake_case}_{index}"
if ptype:
cap_ptype = ptype[0].upper() + ptype[1:]
full_name = f"{cap_ptype} {full_name}"
snake_case += f"_{ptype}"
else:
raise RegistrationDoesNotMatchError
return unit, full_name, snake_case
[docs]def registration_spherical_overdensities(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers SO aperture values by searching them with regex.
"""
# Capture group 1: quantity
# Capture group 2: particle type
# Capture group 3: sf / nsf
# Capture group 4: size of aperture
match_string = "SO_([^_]*)_([a-zA-Z]*)?_?([a-zA-Z]*)?_?([0-9]*)_rhocrit"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
quantity = match.group(1)
ptype = match.group(2)
star_forming = match.group(3)
aperture_size = int(match.group(4))
unit = get_aperture_unit(quantity, unit_system)
name = get_particle_property_name_conversion(quantity, ptype)
if star_forming:
sf_in_name = f"{star_forming.upper()} "
else:
sf_in_name = ""
full_name = f"{sf_in_name}{name} ({aperture_size} $\\rho_{{\\rm crit}}$)"
snake_case = field_path.lower().replace("so_", "")
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
[docs]def registration_element_masses_in_stars(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers element masses contained in stars
"""
unit = unit_system.mass
# Capture aperture size
match_string = "Aperture_([a-zA-Z]*)Masses_aperture_total_star_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
element = match.group(1)
aperture_size = match.group(2)
try:
field = {
"Oxygen": "Total Oxygen mass in stars",
"Magnesium": "Total Magnesium mass in stars",
"Iron": "Total Iron mass in stars",
}[element]
except KeyError:
raise RegistrationDoesNotMatchError
full_name = f"{field} computed in apertures of size ({aperture_size} kpc)"
snake_case = f"{element.lower()}_mass_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
return
[docs]def registration_snia_rates(
field_path: str, unit_system: VelociraptorUnits
) -> (unyt.Unit, str, str):
"""
Registers the SNIa rates within apertures
"""
unit = unit_system.velocity / unit_system.length
# Capture aperture size
match_string = "Aperture_SNIaRates_aperture_total_star_([0-9]*)_kpc"
regex = cached_regex(match_string)
match = regex.match(field_path)
if match:
aperture_size = match.group(1)
full_name = f"SNIa rate ({aperture_size} kpc)"
snake_case = f"snia_rates_{aperture_size}_kpc"
return unit, full_name, snake_case
else:
raise RegistrationDoesNotMatchError
# TODO
# lambda_B
# q
# q_gas
# q_star
# s
# s_gas
# s_star
# sigV
# sigV_gas_nsf
# sigV_gas_sf
# This must be placed at the bottom of the file so that we
# have defined all functions before getting to it.
# This dictionary will be turned into sets of datasets that
# contain the results of the registraiton functions. For example.
# we will have VelociraptorProperties.energies.erot for the rotation
# energy.
global_registration_functions = {
k: globals()[f"registration_{k}"]
for k in [
"snia_rates",
"metallicity",
"ids",
"energies",
"stellar_age",
"spherical_overdensities",
"rotational_support",
"star_formation_rate",
"masses",
"eigenvectors",
"radii",
"temperature",
"veldisp",
"structure_type",
"velocities",
"positions",
"concentration",
"rvmax_quantities",
"angular_momentum",
"projected_apertures",
"apertures",
"element_mass_fractions",
"dust_mass_fractions",
"number",
"hydrogen_phase_fractions",
"black_hole_masses",
"stellar_birth_densities",
"snii_thermal_feedback_densities",
"species_fractions",
"gas_hydrogen_species_masses",
"gas_H_and_He_masses",
"gas_diffuse_element_masses",
"dust_masses_from_table",
"dust_masses",
"stellar_luminosities",
"cold_dense_gas_properties",
"log_element_ratios_times_masses",
"lin_element_ratios_times_masses",
"element_masses_in_stars",
"fail_all",
]
}