From fba9bc28fc781dbd29bdada12cd0f3dcca1caf68 Mon Sep 17 00:00:00 2001 From: Sichao He <1310722434@qq.com> Date: Sun, 22 Dec 2024 11:14:22 +0800 Subject: [PATCH 1/4] Add more constants (`Unit`) --- brainunit/_unit_constants.py | 112 +++++++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 11 deletions(-) diff --git a/brainunit/_unit_constants.py b/brainunit/_unit_constants.py index ae5e9da..cbf4666 100644 --- a/brainunit/_unit_constants.py +++ b/brainunit/_unit_constants.py @@ -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 ----- @@ -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.0e-6) +au = astronomical_unit = Unit.create(meter.dim, name="astronomical unit", dispname="AU", scale=meter.scale + 11, + factor=1.495978707e11) +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 + 4, factor=1.05505585262) +Btu_th = Unit.create(joule.dim, name="British thermal unit (thermochemical)", dispname="Btu th", scale=joule.scale + 4, + 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 + 3, + 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/ +""" \ No newline at end of file From 1a6ab3ea6e66976a8278c3a8699d5fe39d4a37ac Mon Sep 17 00:00:00 2001 From: Sichao He <1310722434@qq.com> Date: Sun, 22 Dec 2024 12:00:02 +0800 Subject: [PATCH 2/4] Add more constants (`Quantity`) --- brainunit/__init__.py | 7 +-- brainunit/_unit_constants.py | 10 ++-- brainunit/constants.py | 109 ++++++++++++++++++++++++++++++----- brainunit/constants_test.py | 35 +++++++++++ 4 files changed, 137 insertions(+), 24 deletions(-) diff --git a/brainunit/__init__.py b/brainunit/__init__.py index 81e48e6..5cea734 100644 --- a/brainunit/__init__.py +++ b/brainunit/__init__.py @@ -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 diff --git a/brainunit/_unit_constants.py b/brainunit/_unit_constants.py index cbf4666..9d6982a 100644 --- a/brainunit/_unit_constants.py +++ b/brainunit/_unit_constants.py @@ -68,9 +68,9 @@ 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=meter.scale - 10, factor=1.0) -micron = Unit.create(meter.dim, name="micron", dispname="µm", scale=meter.scale - 6, factor=1.0e-6) +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.495978707e11) + 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) @@ -116,13 +116,13 @@ 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 + 4, factor=1.05505585262) -Btu_th = Unit.create(joule.dim, name="British thermal unit (thermochemical)", dispname="Btu th", scale=joule.scale + 4, + 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 + 3, +hp = horsepower = Unit.create(watt.dim, name="horsepower", dispname="hp", scale=watt.scale + 2, factor=7.4569987158227022) # ----- Force ----- diff --git a/brainunit/constants.py b/brainunit/constants.py index 151e801..f17e4eb 100644 --- a/brainunit/constants.py +++ b/brainunit/constants.py @@ -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: @@ -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 @@ -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 diff --git a/brainunit/constants_test.py b/brainunit/constants_test.py index 06add7e..bb687ef 100644 --- a/brainunit/constants_test.py +++ b/brainunit/constants_test.py @@ -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): @@ -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" From 3ff33c716018f085e3539efa1c921dbe4bcbdb94 Mon Sep 17 00:00:00 2001 From: Sichao He <1310722434@qq.com> Date: Sun, 22 Dec 2024 12:03:04 +0800 Subject: [PATCH 3/4] Fix bug --- brainunit/math/_fun_keep_unit.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/brainunit/math/_fun_keep_unit.py b/brainunit/math/_fun_keep_unit.py index 4af911d..285a694 100644 --- a/brainunit/math/_fun_keep_unit.py +++ b/brainunit/math/_fun_keep_unit.py @@ -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', @@ -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( From d2b57c005971af97857a9ab472c3b2dff9a832e4 Mon Sep 17 00:00:00 2001 From: Sichao He <1310722434@qq.com> Date: Sun, 22 Dec 2024 12:06:10 +0800 Subject: [PATCH 4/4] Update _fun_keep_unit_test.py --- brainunit/math/_fun_keep_unit_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brainunit/math/_fun_keep_unit_test.py b/brainunit/math/_fun_keep_unit_test.py index 23b0796..b489b3c 100644 --- a/brainunit/math/_fun_keep_unit_test.py +++ b/brainunit/math/_fun_keep_unit_test.py @@ -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 = [