alkahest.units
alkahest.units — physical units, quantities and dimensional analysis.
A Unit is a product of named units with rational exponents over
the seven SI base dimensions, carrying an exact scale relative to SI
(1 inch = 127/5000 m, 1 deg = π/180 rad — never a float). A
Quantity pairs a value (an Expr, int or Fraction) with a
unit, and its arithmetic checks dimensions:
+/-need equal dimensions (UnitErrorE-UNIT-001names both) and convert the right operand exactly into the left operand's unit;*///**(rational exponent) combine units;exp(),log(),sin(), … need a dimensionless argument (E-UNIT-004); an angle indegis converted toradfirst;degC/degFare affine scales: they can beconvert()ed and nothing else (E-UNIT-003).
dimension_of() checks a whole symbolic formula given each symbol's unit,
and diff() / integrate() carry units through calculus
(∫ C dt of a concentration over time is in mg*h/L).
Example
>>> from alkahest import ExprPool
>>> from alkahest.units import Quantity, convert
>>> convert(Quantity(1, "inch"), "m").value
Fraction(127, 5000)A value together with its Unit.
valueExpr, int, Fraction or floatThe magnitude. Use
int/Fraction/Exprfor exact work; afloatis kept as given (conversions never introduce one).unitUnit or str, default"1"The unit, e.g.
"mg","L/h",Unit("m/s^2").
Arithmetic checks dimensions (see the module docstring). Comparison with
== is identity; compare convert(a, b.unit).value with b.value
instead.
>>> m = Quantity(2, "kg"); a = Quantity(3, "m/s^2")
>>> (m * a).unit == Unit("N")
TrueMerge factors of equal dimension (mg/kg*g → mg, km/m → 1)
and, with derived=True (default), rename an exact match to a named
SI derived unit (kg*m/s^2 → N). See simplify_units().
A physical unit: a product of named units with rational exponents, an exact scale relative to SI, and a dimension over the seven SI base dimensions.
Build one from a string — Unit("mg*h/L"), Unit("m/s^2"),
Unit("kg m s^-2"), Unit("m^(1/2)"), Unit("µg/mL") — or by
combining units with *, / and ** (rational exponent).
Equality is semantic: Unit("N") == Unit("kg*m/s^2") is True;
str(u) keeps the spelling. degC / degF are affine scales and
may only stand alone and be converted (E-UNIT-003 otherwise).
Raises UnitError (E-UNIT-002) on an unknown or malformed unit.
(ratio, pi_power): one of this unit is ratio · π**pi_power of the
coherent SI unit of the same dimension (both Fraction).
Raise UnitError E-UNIT-001 (naming both dimensions) unless
other has the same dimension.
Raise UnitError E-UNIT-004 unless this is a pure number;
context names where the value is used ("argument of exp").
The exact map x [self] = ratio·π**pi_power·x + shift [target] as
(ratio, pi_power, shift) (Fractions; shift is 0 except
between affine temperature scales). E-UNIT-001 on a dimension
mismatch.
The coherent SI unit of the same dimension in base units
(Unit("J").to_base() is kg*m^2/s^2).
Merge factors of equal dimension (mg/kg*g → mg); returns
(ratio, pi_power, unit) with x [self] = ratio·π**pi_power·x [unit].
With derived=True the merged unit is also renamed to the named SI
derived unit it exactly equals (kg*m/s^2 → N), see
to_derived(); allowed restricts the candidate names.
The named SI derived unit this unit exactly equals, or None.
Unit("kg*m/s^2").to_derived() is N; g*m/s^2 is mN
(prefixes in steps of 1000 only); kg*cm/s^2 is not renamed (its
scale is not a power of 1000 times N). The candidates are N, Pa, J, W, C, V, ohm, F, H, T, Wb, S, Hz` (`allowed restricts them). A
unit that is already one named factor, is dimensionless or affine, or
contains a dimensionless factor (rad/s is not Hz) is left
alone, and Gy/Sv/Bq are never produced (they share a
dimension with m^2/s^2 and Hz). N*m is a J.
No docstring.
Apply a function that needs a pure-number argument (exp, log,
trigonometric, …) to q.
A dimensionless q with a scale (deg, %) is converted to a pure
number first, so sin(Quantity(90, "deg")) is sin(π/2). A
dimensional q is refused with UnitError E-UNIT-004.
The pH of a hydrogen-ion concentration: -log10(c / (1 mol/L)).
c is a Quantity of amount per volume (any unit; it is
converted exactly to mol/L first). Exact for powers of ten
(Fraction(1, 10**7) mol/L → 7), symbolic otherwise; UnitError
E-UNIT-001 for another dimension, ValueError for a concentration
≤ 0.
Express q in unit, exactly.
The value is multiplied by the exact ratio of the two scales (and, between
degC/degF/K/degR, shifted by the exact offset).
Raises UnitError E-UNIT-001 when the dimensions differ.
>>> convert(Quantity(100, "degC"), "degF").value
212The ratio a level in decibels stands for: 10**(db/10) for a power
quantity (kind="power", default) and 10**(db/20) for a field
quantity (kind="field": voltage, current, pressure, amplitude).
Exact: db_to_ratio(30) is 1000 and db_to_ratio(3) the symbolic
10**(3/10) — never a float unless the input is one. db may be a
number, an Expr or a pure-number Quantity. The inverse is
ratio_to_db(). There is no dB unit and no dB arithmetic:
Unit("dB") is refused with a pointer here.
>>> db_to_ratio(20, "field")
10d q / d var with unit q.unit / var.unit.
var is a Quantity whose value is a symbol, e.g.
Quantity(t, "h").
>>> # x(t) in m, t in s → dx/dt in m/sThe unit of a symbolic formula, given the unit of each of its symbols.
Checks the dimensional consistency of expr and returns the unit
its value is in when every symbol is given in its listed unit.
exprExprThe formula.
unitsdict[Expr, Unit | str]The unit of each symbol. Keys may be any sub-expression, e.g. an applied undefined function
C(t).
- Unit
- UnitError
E-UNIT-001the terms of a sum have different dimensions (both are named);E-UNIT-004the argument ofexp/log/sin/… or a non-literal exponent is not a pure number (an angle must be inrad);E-UNIT-005a symbol or function with no known unit;E-UNIT-006the terms of a sum share a dimension but not a unit (handmin);E-UNIT-003an affine temperature inside arithmetic.
>>> p = ExprPool(); D, V = p.symbol("D"), p.symbol("V")
>>> dimension_of(D / V, {D: "mg", V: "L"})
Unit('mg/L')∫ q d var with unit q.unit · var.unit.
var is a Quantity whose value is a symbol, e.g.
Quantity(t, "h"). Bounds may be quantities (converted exactly into
var's unit) or the unit-free 0 and ±oo; a bare number for a
dimensional variable is refused (E-UNIT-001), because its unit is
unknown.
>>> # AUC: ∫_0^∞ C(t) dt with C in mg/L and t in h is in mg*h/L.Every unit name the parser knows (without SI prefixes), sorted.
The ratio a level in nepers stands for: exp(np) for a field
quantity (default) and exp(2·np) for a power quantity. Exact
(exp(...) stays symbolic; 0 Np is 1).
Parse a unit string into a Unit.
Accepts products and quotients ("mg*h/L", "kg m s^-2",
"kg*m^2/(s^2*A)"), exponents with ^ or ** (fractional ones in
parentheses, "m^(1/2)") or Unicode superscripts ("m s⁻²"), SI
prefixes from yocto to yotta (µ, μ and u all mean micro), and
exact numeric factors ("1000*m"). / divides by the single factor that
follows it.
Raises UnitError: E-UNIT-002 for a malformed string or an unknown
name ("m2" is refused, not read as m^2), E-UNIT-003 for an
affine temperature unit inside a compound unit ("degC/s").
>>> parse_unit("mg*h/L").dimension
'mass*time/length^3'The hydrogen-ion concentration of a pH as a Quantity in
mol/L: 10**(-pH) (pH 7 is Fraction(1, 10**7)), taking the
IUPAC standard state of 1 mol/L (activity ≈ concentration). The inverse
is concentration_to_ph().
The level in decibels of a positive ratio: 10·log10(ratio) for a
power quantity, 20·log10(ratio) for a field quantity. Exact for exact
powers of ten (ratio_to_db(1000) is 30), symbolic otherwise
(Expr in, 10*log(r)/log(10) out). ValueError for a ratio ≤ 0.
>>> ratio_to_db(100, "field")
40The level in nepers of a positive ratio: ln(ratio) for a field
quantity, ln(ratio)/2 for a power quantity. ratio_to_np(1) is
0; ValueError for a ratio ≤ 0.
Merge the factors of q.unit that share a dimension into the first
one (mg/kg*g → mg, L/h*min → L, km/m → 1), folding the exact
conversion ratio into the value; then, unless derived=False, rename the
result to the named SI derived unit it exactly equals.
qQuantityderivedbool, default Truekg*m/s^2 → N,kg*m^2/s^2 → J,A*s → C,kg*m^2/(A*s^3) → V`; a power-of-1000 prefix is allowed (`g*m/s^2 → mN). The candidates areN, Pa, J, W, C, V, ohm, F, H, T, Wb, S, Hz(their dimensions are pairwise distinct, so there is no ambiguity among them;N*mis aJ). A unit that is already a single named factor, carries a dimensionless factor (rad/sis notHz) or whose scale is not a power of 1000 times the derived unit (kg*cm/s^2) is left as is.Gy,SvandBqare never produced.allowediterable of str, optionalRestrict the candidates, e.g.
allowed=["N", "J"].
>>> simplify_units(Quantity(3, "kg*m/s^2")).unit
Unit('N')
>>> simplify_units(Quantity(3, "kg*m/s^2"), derived=False).unit
Unit('kg*m/s^2')q ** (1/2); the unit's scale must have an exact square root
(E-UNIT-007 otherwise, e.g. km).
Express q in coherent SI base units (kg, m, s, A,
K, mol, cd); degC/degF go to K.
acos = _fn('acos')No docstring.
asin = _fn('asin')No docstring.
atan = _fn('atan')No docstring.
cos = _fn('cos')No docstring.
cosh = _fn('cosh')No docstring.
exp = _fn('exp')No docstring.
log = _fn('log')No docstring.
sin = _fn('sin')No docstring.
sinh = _fn('sinh')No docstring.
tan = _fn('tan')No docstring.
tanh = _fn('tanh')No docstring.