Skip to content

Commit

Permalink
add a simulation unit system class
Browse files Browse the repository at this point in the history
  • Loading branch information
adrn committed Sep 26, 2024
1 parent d1bbbfa commit 6b501e6
Showing 1 changed file with 49 additions and 30 deletions.
79 changes: 49 additions & 30 deletions gala/units.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,17 @@
__all__ = [
"UnitSystem",
"DimensionlessUnitSystem",
"SimulationUnitSystem",
"galactic",
"dimensionless",
"solarsystem",
]

import astropy.constants as const

# Third-party
import astropy.units as u
import numpy as np
from astropy.units.physical import _physical_unit_mapping

_greek_letters = [
"alpha",
"beta",
"gamma",
"delta",
"epsilon",
"zeta",
"eta",
"theta",
"iota",
"kappa",
"lambda",
"mu",
"nu",
"xi",
"pi",
"o",
"rho",
"sigma",
"tau",
"upsilon",
"phi",
"chi",
"psi",
"omega",
]


class UnitSystem:
_required_physical_types = [
Expand Down Expand Up @@ -112,7 +85,7 @@ def __init__(self, units, *args):
new_unit = u.def_unit(f"{q!s}", q)
unit = new_unit

typ = unit.physical_type
typ = unit.decompose().physical_type
if typ in self._registry:
raise ValueError(f"Multiple units passed in with type '{typ}'")
self._registry[typ] = unit
Expand Down Expand Up @@ -262,6 +235,52 @@ def get_constant(self, name):
raise ValueError("Cannot get constant in dimensionless units!")


l_pt = u.get_physical_type("length")
m_pt = u.get_physical_type("mass")
t_pt = u.get_physical_type("time")
v_pt = u.get_physical_type("velocity")
a_pt = u.get_physical_type("angle")


class SimulationUnitSystem(UnitSystem):
def __init__(
self,
length: u.Unit | u.Quantity[l_pt] = None,
mass: u.Unit | u.Quantity[m_pt] = None,
time: u.Unit | u.Quantity[t_pt] = None,
velocity: u.Unit | u.Quantity[v_pt] = None,
G: float | u.Quantity = 1.0,
angle: u.Unit | u.Quantity[a_pt] = u.radian,
):
"""
Represents a system of units for a (dynamical) simulation.
A common assumption is that G=1. If this is the case, then you only have to
specify two of the three fundamental unit types (length, mass, time) and the
rest will be derived from these. You may also optionally specify a velocity with
one of the base unit types (length, mass, time).
"""
G = G * const.G.unit

if length is not None and mass is not None:
time = 1 / np.sqrt(G * mass / length**3)
elif length is not None and time is not None:
mass = 1 / G * length**3 / time**2
elif length is not None and velocity is not None:
time = length / velocity
mass = 1 / G / velocity**2 / length
elif mass is not None and time is not None:
length = np.cbrt(G * mass * time**2)
elif mass is not None and velocity is not None:
length = G * mass / velocity**2
elif time is not None and velocity is not None:
mass = 1 / G * velocity**3 * time
length = G * mass / velocity**2

super().__init__(length, mass, time, angle)


# define galactic unit system
galactic = UnitSystem(u.kpc, u.Myr, u.Msun, u.radian, u.km / u.s)

Expand Down

0 comments on commit 6b501e6

Please sign in to comment.