Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Add more constants (Unit and Quantity format) #83

Merged
merged 4 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions brainunit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@
from ._unit_constants import *
from ._unit_shortcuts import *
from ._unit_shortcuts import __all__ as _std_units_all
from .constants import *
from .constants import __all__ as _constants_all
# from .constants import *
# from .constants import __all__ as _constants_all

__all__ = (
['math', 'linalg', 'autograd', 'fft', 'constants', 'sparse'] +
_common_all +
_std_units_all +
_constants_all +
_base_all +
_celsius_all
)
del _common_all, _std_units_all, _constants_all, _base_all, _celsius_all, _matplotlib_compat
del _common_all, _std_units_all, _base_all, _celsius_all, _matplotlib_compat
112 changes: 101 additions & 11 deletions brainunit/_unit_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,34 @@
# ==============================================================================

from ._base import Unit
from ._unit_common import joule, kilogram, second, meter
from ._unit_common import joule, kilogram, second, meter, radian, pascal, meter2, meter3, kelvin, watt, newton
from .math import pi

# ----- Mass -----
metric_ton = Unit.create(kilogram.dim, name="metric ton", dispname="t", scale=kilogram.scale + 3)
grain = Unit.create(kilogram.dim, name="grain", dispname="gr", scale=kilogram.scale - 5, factor=6.479891)
lb = pound = Unit.create(kilogram.dim, name="pound", dispname="lb", scale=kilogram.scale, factor=0.45359237)
slinch = blob = Unit.create(kilogram.dim, name="blob", dispname="blob", scale=kilogram.scale + 2, factor=1.75126836)
slug = Unit.create(kilogram.dim, name="slug", dispname="slug", scale=kilogram.scale + 1, factor=1.459390294)
oz = ounce = Unit.create(kilogram.dim, name="ounce", dispname="oz", scale=kilogram.scale - 2, factor=2.8349523125)
stone = Unit.create(kilogram.dim, name="stone", dispname="st", scale=kilogram.scale, factor=6.35029318)
long_ton = Unit.create(kilogram.dim, name="long ton", dispname="long ton", scale=kilogram.scale + 3,
factor=1.0160469088)
short_ton = Unit.create(kilogram.dim, name="short ton", dispname="short ton", scale=kilogram.scale + 3,
factor=0.90718474)
troy_ounce = Unit.create(kilogram.dim, name="troy ounce", dispname="oz t", scale=kilogram.scale - 2, factor=3.11034768)
troy_pound = Unit.create(kilogram.dim, name="troy pound", dispname="lb t", scale=kilogram.scale, factor=0.3732417216)
carat = Unit.create(kilogram.dim, name="carat", dispname="ct", scale=kilogram.scale - 4, factor=2.)
# atomic mass unit (amu)
atomic_mass = u = um_u = Unit.create(kilogram.dim, name="atomic mass unit", dispname="u", scale=kilogram.scale - 27,
factor=1.66053886)

# ----- Angle -----
degree = Unit.create(radian.dim, name="degree", dispname="°", scale=radian.scale, factor=pi / 180)
arcmin = arcminute = Unit.create(radian.dim, name="arcminute", dispname="′", scale=radian.scale - 4,
factor=2.908882086657216)
arcsec = arcsecond = Unit.create(radian.dim, name="arcsecond", dispname="″", scale=radian.scale - 6,
factor=4.84813681109536)

# ----- Time -----

Expand All @@ -40,20 +67,83 @@
factor=1.6093472186944374)
nautical_mile = Unit.create(meter.dim, name="nautical mile", dispname="nmi", scale=meter.scale + 3, factor=1.8520)
fermi = Unit.create(meter.dim, name="fermi", dispname="fm", scale=meter.scale - 15)
angstrom = Unit.create(meter.dim, name="angstrom", dispname="Å", scale=-10, factor=1.0)
micron = Unit.create(meter.dim, name="micron", dispname="µm", scale=-6, factor=1.0e-6)
astronomical_unit = Unit.create(meter.dim, name="astronomical unit", dispname="AU", scale=11, factor=1.495978707e11)
light_year = Unit.create(meter.dim / second.dim, name="light year", dispname="ly", scale=11, factor=1.094991952845)
angstrom = Unit.create(meter.dim, name="angstrom", dispname="Å", scale=meter.scale - 10, factor=1.0)
micron = Unit.create(meter.dim, name="micron", dispname="µm", scale=meter.scale - 6, factor=1.)
au = astronomical_unit = Unit.create(meter.dim, name="astronomical unit", dispname="AU", scale=meter.scale + 11,
factor=1.495978707)
light_year = Unit.create(meter.dim, name="light year", dispname="ly", scale=meter.scale + 15, factor=9.460730777119564)
parsec = Unit.create(meter.dim, name="parsec", dispname="pc", scale=meter.scale + 16, factor=3.085677581491367e16)

# ----- Pressure -----
atm = atmosphere = Unit.create(pascal.dim, name="atmosphere", dispname="atm", scale=meter.scale + 5, factor=1.013249966)
bar = Unit.create(pascal.dim, name="bar", dispname="bar", scale=meter.scale + 5, factor=1.)
mmHg = torr = Unit.create(pascal.dim, name="torr", dispname="torr", scale=meter.scale + 2, factor=1.3332236842105263)
psi = Unit.create(pascal.dim, name="pound per square inch", dispname="psi", scale=meter.scale + 3,
factor=6.894757293168361)

# ----- Area -----
hectare = Unit.create(meter2.dim, name="hectare", dispname="ha", scale=meter2.scale + 4, factor=1.)
acre = Unit.create(meter2.dim, name="acre", dispname="acre", scale=meter2.scale + 3, factor=4.046864798)

# ----- Volume -----
gallon = gallon_US = Unit.create(meter3.dim, name="gallon", dispname="gal", scale=meter3.scale - 3, factor=3.785411784)
gallon_imp = Unit.create(meter3.dim, name="imperial gallon", dispname="gal", scale=meter3.scale - 3, factor=4.54609)
fluid_ounce = fluid_ounce_US = Unit.create(meter3.dim, name="fluid ounce", dispname="fl oz", scale=meter3.scale - 5,
factor=2.95735295625)
fluid_ounce_imp = Unit.create(meter3.dim, name="imperial fluid ounce", dispname="fl oz imp", scale=meter3.scale - 5,
factor=2.84130742)
bbl = barrel = Unit.create(meter3.dim, name="barrel", dispname="bbl", scale=meter3.scale + 2, factor=1.5898729493)

# ----- Speed -----
speed_unit = meter / second
kmh = Unit.create(speed_unit.dim, name="kilometer per hour", dispname="km/h", scale=speed_unit.scale - 1,
factor=2.77777778)
mph = Unit.create(speed_unit.dim, name="mile per hour", dispname="mph", scale=speed_unit.scale - 1, factor=4.4704)
mach = speed_of_sound = Unit.create(speed_unit.dim, name="speed of sound", dispname="mach", scale=speed_unit.scale + 2,
factor=3.4029)
knot = Unit.create(speed_unit.dim, name="knot", dispname="kn", scale=speed_unit.scale - 1, factor=5.14444444)

# ----- Temperature -----
# TODO: The relationship between Celsius and Kelvin should be linear, but the current implementation is not.
# zero_Celsius = Unit.create(kelvin.dim, name="zero Celsius", dispname="0°C", scale=kelvin.scale, factor=273.15)
degree_Fahrenheit = Unit.create(kelvin.dim, name="degree Fahrenheit", dispname="°F", scale=kelvin.scale + 2,
factor=2.55927778)

# ----- Energy -----
eV = electron_volt = Unit.create(joule.dim, name="electronvolt", dispname="eV", scale=-19, factor=1.602176565)
calorie = calorie_th = Unit.create(joule.dim, name="calorie", dispname="cal", scale=joule.scale, factor=4.184)
calorie_IT = Unit.create(joule.dim, name="calorie (International Table)", dispname="cal IT", scale=joule.scale,
factor=4.1868)
erg = Unit.create(joule.dim, name="erg", dispname="erg", scale=joule.scale - 7, factor=1.)
Btu = Btu_IT = Unit.create(joule.dim, name="British thermal unit (International Table)", dispname="Btu IT",
scale=joule.scale + 3, factor=1.05505585262)
Btu_th = Unit.create(joule.dim, name="British thermal unit (thermochemical)", dispname="Btu th", scale=joule.scale + 3,
factor=1.0543499999744)
ton_TNT = Unit.create(joule.dim, name="ton of TNT", dispname="ton TNT", scale=joule.scale + 9, factor=4.184)

# ----- Power -----
hp = horsepower = Unit.create(watt.dim, name="horsepower", dispname="hp", scale=watt.scale + 2,
factor=7.4569987158227022)

# ----- Force -----
dyn = dyne = Unit.create(newton.dim, name="dyne", dispname="dyn", scale=newton.scale - 5, factor=1.)
lbf = pound_force = Unit.create(newton.dim, name="pound force", dispname="lbf", scale=newton.scale,
factor=4.4482216152605)
kgf = kilogram_force = Unit.create(newton.dim, name="kilogram force", dispname="kgf", scale=newton.scale,
factor=9.80665)

# UNITS in modular dynamics
# See https://github.com/chaobrain/brainunit/issues/63

electron_volt = Unit.create(joule.dim, name="electronvolt", dispname="eV", scale=-19, factor=1.602176565)
elementary_charge = eV = electron_volt
# atomic mass unit (amu)
AMU = Unit.create(kilogram.dim, name="atomic mass unit", dispname="AMU", scale=-27, factor=1.66053886)
# Intermolecular force 分子间作用力
IMF = Unit.create(eV.dim / angstrom.dim, name="intermolecular force", dispname="IMF", scale=-9, factor=1.602176565)
IMF = Unit.create(newton.dim, name="intermolecular force", dispname="IMF", scale=newton.scale - 9, factor=1.602176565)

""""
References
==========

.. [CODATA2018] CODATA Recommended Values of the Fundamental
Physical Constants 2018.

https://physics.nist.gov/cuu/Constants/

"""
109 changes: 94 additions & 15 deletions brainunit/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
have to be imported explicitly. You can use ``import ... as ...`` to import them
with shorter names, e.g.::

from brainunit import faraday_constant as F
from brainunit.constants import faraday_constant as F

The available constants are:

Expand Down Expand Up @@ -51,21 +51,9 @@
kilogram,
meter,
mole,
newton,
newton, radian, second, pascal, meter2, meter3, watt,
)

__all__ = [
'avogadro_constant',
'boltzmann_constant',
'electric_constant',
'electron_mass',
'elementary_charge',
'faraday_constant',
'gas_constant',
'magnetic_constant',
'molar_mass_constant',
'zero_celsius',
]
from ._unit_constants import speed_unit

#: Avogadro constant (http://physics.nist.gov/cgi-bin/cuu/Value?na)
avogadro_constant = np.asarray(6.022140857e23) / mole
Expand All @@ -87,3 +75,94 @@
molar_mass_constant = np.asarray(1.) * (gram / mole)
#: zero degree Celsius
zero_celsius = np.asarray(273.15) * kelvin

# ----- Mass -----
metric_ton = np.asarray(1e3) * kilogram # Metric ton
grain = np.asarray(6.479891e-5) * kilogram # Grain
lb = pound = np.asarray(0.45359237) * kilogram # Pound
slinch = blob = np.asarray(1.75126836e2) * kilogram # Blob (slug-inch)
slug = np.asarray(1.459390294e1) * kilogram # Slug
oz = ounce = np.asarray(2.8349523125e-2) * kilogram # Ounce
stone = np.asarray(6.35029318) * kilogram # Stone
long_ton = np.asarray(1.0160469088e3) * kilogram # Long ton
short_ton = np.asarray(0.90718474e3) * kilogram # Short ton
troy_ounce = np.asarray(3.11034768e-2) * kilogram # Troy ounce
troy_pound = np.asarray(0.3732417216) * kilogram # Troy pound
carat = np.asarray(2e-4) * kilogram # Carat
atomic_mass = np.asarray(1.66053886e-27) * kilogram # Atomic mass unit (amu)

# ----- Angle -----
degree = np.asarray(np.pi / 180) * radian # Degree
arcmin = arcminute = np.asarray(np.pi / (180 * 60)) * radian # Arcminute
arcsec = arcsecond = np.asarray(np.pi / (180 * 3600)) * radian # Arcsecond

# ----- Time -----
minute = np.asarray(60) * second # Minute
hour = np.asarray(3600) * second # Hour
day = np.asarray(86400) * second # Day
week = np.asarray(604800) * second # Week
month = np.asarray(2.629746e6) * second # Month (approx.)
year = np.asarray(3.1556952e7) * second # Year (approx.)
julian_year = np.asarray(3.15576e7) * second # Julian year

# ----- Length -----
inch = np.asarray(0.0254) * meter # Inch
foot = np.asarray(0.3048) * meter # Foot
yard = np.asarray(0.9144) * meter # Yard
mile = np.asarray(1609.344) * meter # Mile
mil = np.asarray(2.54e-5) * meter # Mil
point = np.asarray(3.5277777777777776e-4) * meter # Point
pica = np.asarray(4.233333333333333e-3) * meter # Pica
survey_foot = np.asarray(0.3048006096012192) * meter # Survey foot
survey_mile = np.asarray(1609.3472186944374) * meter # Survey mile
nautical_mile = np.asarray(1852) * meter # Nautical mile
fermi = np.asarray(1e-15) * meter # Fermi
angstrom = np.asarray(1e-10) * meter # Ångstrom
micron = np.asarray(1e-6) * meter # Micron
au = astronomical_unit = np.asarray(1.495978707e11) * meter # Astronomical unit
light_year = np.asarray(9.460730777119564e15) * meter # Light year
parsec = np.asarray(3.085677581491367e16) * meter # Parsec

# ----- Pressure -----
atm = atmosphere = np.asarray(1.013249966e5) * (newton / meter2) # Atmosphere
bar = np.asarray(1e5) * (newton / meter2) # Bar
mmHg = torr = np.asarray(1.3332236842105263e2) * (newton / meter2) # Torr (mmHg)
psi = np.asarray(6.894757293168361e3) * (newton / meter2) # Pound per square inch (psi)

# ----- Area -----
hectare = np.asarray(1e4) * meter2 # Hectare
acre = np.asarray(4046.864798) * meter2 # Acre

# ----- Volume -----
gallon = gallon_US = np.asarray(3.785411784e-3) * meter3 # Gallon (US)
gallon_imp = np.asarray(4.54609e-3) * meter3 # Imperial gallon
fluid_ounce = fluid_ounce_US = np.asarray(2.95735295625e-5) * meter3 # Fluid ounce (US)
fluid_ounce_imp = np.asarray(2.84130742e-5) * meter3 # Imperial fluid ounce
bbl = barrel = np.asarray(1.58987294928e2) * meter3 # Barrel (oil)

# ----- Temperature -----
degree_Fahrenheit = np.asarray(2.55927778e2) * kelvin # Fahrenheit

# ----- Speed -----
kmh = np.asarray(2.77777778e-1) * speed_unit # Kilometer per hour
mph = np.asarray(4.4704e-1) * speed_unit # Mile per hour
knot = np.asarray(5.14444444e-1) * speed_unit # Knot
mach = np.asarray(3.4029e2) * speed_unit # Mach

# ----- Energy -----
eV = electronvolt = np.asarray(1.6021766208e-19) * joule # Electronvolt
calorie = calorie_th = np.asarray(4.184) * joule # Calorie (thermochemical)
calorie_IT = np.asarray(4.1868) * joule # Calorie (International Table)
erg = np.asarray(1e-7) * joule # Erg
Btu = Btu_IT = np.asarray(1.05505585262e3) * joule # British thermal unit (International Table)
Btu_th = np.asarray(1.05435026444e3) * joule # British thermal unit (thermochemical)
ton_TNT = np.asarray(4.184e9) * joule # Ton of TNT

# ----- Power -----
hp = horsepower = np.asarray(7.4569987158227022e2) * watt # Horsepower

# ----- Force -----
dyn = dyne = np.asarray(1e-5) * newton # Dyne
lbf = pound_force = np.asarray(4.4482216152605) * newton # Pound-force
kgf = kilogram_force = np.asarray(9.80665) * newton # Kilogram-force
IMF = np.asarray(1.602176565e-9) * newton # Intermolecular force
35 changes: 35 additions & 0 deletions brainunit/constants_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,34 @@
import brainunit as u
from brainunit._unit_common import *

constants_list = [
# Mass
'metric_ton', 'grain', 'pound', 'slinch', 'slug', 'ounce', 'stone', 'long_ton', 'short_ton', 'troy_ounce',
'troy_pound', 'carat', 'atomic_mass',
# Angle
'degree', 'arcmin', 'arcsec',
# Time
'minute', 'hour', 'day', 'week', 'month', 'year', 'julian_year',
# Length
'inch', 'foot', 'yard', 'mile', 'mil', 'point', 'pica', 'survey_foot', 'survey_mile', 'nautical_mile', 'fermi',
'angstrom', 'micron', 'au', 'light_year',
# Pressure
'atm', 'bar', 'mmHg', 'psi',
# Area
'hectare', 'acre',
# Volume
'gallon', 'gallon_imp', 'fluid_ounce', 'fluid_ounce_imp', 'bbl',
# Speed
'kmh', 'mph', 'knot', 'mach',
# Temperature
'degree_Fahrenheit',
# Energy
'eV', 'calorie', 'calorie_IT', 'erg', 'Btu', 'Btu_IT', 'ton_TNT',
# Power
'hp',
# Force
'dyn', 'lbf', 'kgf', 'IMF',
]

class TestConstant(unittest.TestCase):

Expand Down Expand Up @@ -45,3 +73,10 @@ def test_constants(self):
constants.faraday_constant.mantissa,
(constants.avogadro_constant * constants.elementary_charge).mantissa,
)
def test_quantity_constants_and_unit_constants(self):
import brainunit.constants as quantity_constants
import brainunit._unit_constants as unit_constants
for c in constants_list:
q_c = getattr(quantity_constants, c)
u_c = getattr(unit_constants, c)
assert q_c.to_decimal(q_c.unit) == (1. * u_c).to_decimal(q_c.unit), f"Mismatch between {c} in quantity_constants and unit_constants"
20 changes: 1 addition & 19 deletions brainunit/math/_fun_keep_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
'percentile', 'nanpercentile', 'quantile', 'nanquantile',

# math funcs only accept unitless (unary) can return Quantity
'round', 'around', 'round_', 'rint', 'floor', 'ceil', 'trunc', 'fix', 'modf',
'round', 'around', 'rint', 'floor', 'ceil', 'trunc', 'fix', 'modf',

# math funcs keep unit (binary)
'fmod', 'mod', 'copysign', 'remainder',
Expand Down Expand Up @@ -3377,24 +3377,6 @@ def unique(
fill_value=fill_value)


@set_module_as('brainunit.math')
def round_(
x: Union[Quantity, jax.typing.ArrayLike],
) -> jax.Array | Quantity:
"""
Round an array to the nearest integer.

Parameters
----------
x : array_like, Quantity
Input array.

Returns
-------
out : jax.Array
"""
return _fun_keep_unit_unary(jnp.round, x)


@set_module_as('brainunit.math')
def round(
Expand Down
2 changes: 1 addition & 1 deletion brainunit/math/_fun_keep_unit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
]

fun_accept_unitless_unary_can_return_quantity = [
'round', 'around', 'round_', 'rint',
'round', 'around', 'rint',
'floor', 'ceil', 'trunc', 'fix',
]
fun_keep_unit_math_binary = [
Expand Down
Loading