units
utils.units
Unit and Dimension Utilities.
Central mapping between TVBO’s UnitEnum (QUDT-backed), a backend’s own unit vocabulary, SymPy units, and legacy free-text unit strings found in older model YAMLs.
The UnitEnum values use conventional abbreviations (ms, mV, nA, etc.) as defined in the LinkML schema (schema/tvbo_datamodel.yaml).
unit_to_lems_dimension(unit)— map a UnitEnum value to a LEMS dimension nameunit_to_lems_symbol(unit)— map a UnitEnum value to the LEMS unit symbolunit_has_time_dimension(unit)— whether the unit carries a time componentnormalize_unit(raw)— convert legacy free-text strings to UnitEnum values
Attributes
| Name | Description |
|---|---|
| DEFAULT_TIME_UNIT |
Functions
| Name | Description |
|---|---|
| normalize_unit | Convert a legacy free-text unit string to a UnitEnum value name. |
| time_unit_factor | The exact factor converting a time-valued number from one scope’s unit to another’s. |
| time_unit_of | The time unit governing scopes, resolved outwards, ms if nobody declares one. |
| unit_dimensions | Base-dimension exponents of unit as {base unit name: Fraction}. |
| unit_expression | unit as a SymPy expression over SI base quantities, or None if uncurated. |
| unit_facts | The vendored QUDT record for unit, or None if it is not curated. |
| unit_has_time_dimension | Return True if the unit carries a time component (T or T⁻¹). |
| unit_multiplier | The exact Fraction scaling unit onto SI base units, or None if uncurated. |
| unit_named | The one curated unit whose expression is exactly expression, or None. |
| unit_to_latex | Return a LaTeX string for the unit, suitable for wrapping in $...$. |
| unit_to_lems_dimension | Return the LEMS dimension name for a UnitEnum value (or string). |
| unit_to_lems_symbol | Return the LEMS unit symbol string for appending to numeric values. |
| unit_to_si_factor | Return the multiplicative factor to convert from unit to SI base units. |
| unit_to_symbol | Return the conventional display symbol for a UnitEnum value. |
normalize_unit
utils.units.normalize_unit(raw)Convert a legacy free-text unit string to a UnitEnum value name.
Accepts abbreviations, full names, slash notation, and exponent notation. Returns None if the string cannot be mapped — which is the answer for a unit that is real but uncurated, such as kg/ms^2: the slot records it as written rather than rounding it to the nearest curated name it is not equal to.
normalize_unit(“mV”) ‘mV’ normalize_unit(“millivolt”) ‘mV’ normalize_unit(“ms^-1”) ‘per_ms’ normalize_unit(“kg/s^2”) ‘N_per_m’ normalize_unit(None)
time_unit_factor
utils.units.time_unit_factor(from_scope, to_scope)The exact factor converting a time-valued number from one scope’s unit to another’s.
Either side may be a single scope or a tuple of them resolved innermost-first, so a subnetwork can be asked with its enclosing scopes: one that declares no unit of its own inherits the parent’s, and the factor is then exactly 1 rather than a conversion onto the fallback.
Fraction, not float: a subnetwork in s folding into a parent in ms is exactly 1000, and a factor of 1000 living only in a modeller’s head is invisible in every backend’s output — which is the error this exists to catch.
Raises
| Name | Type | Description |
|---|---|---|
| ValueError | If either unit is not time-valued, or they are dimensionally incompatible — a silent conversion between them would be worse than none. |
time_unit_of
utils.units.time_unit_of(*scopes)The time unit governing scopes, resolved outwards, ms if nobody declares one.
Every time-valued number in a scope — step_size, period, downsample_period, simulation_period, sampling_period — is in the unit this returns. Pass the scopes innermost first (time_unit_of(node.subnetwork, network, integrator, experiment)); the first that declares a unit wins, and None entries are skipped so callers need not pre-filter. A scope’s own integration is consulted before moving outwards, so passing a Network is enough to reach the clock it declares.
This is the only place the ms fallback is stated. It used to be stated in every scope at once through ifabsent: ms, which made an unset unit indistinguishable from a written one and so could not be inherited through — and separately at each call site, where the defaults had already drifted apart ("s" in one branch of the NeuroML adapter, "ms" in the others, and a LEMS emitter that appended ms unconditionally while its sibling read the declaration). A model in the database declares s, so those disagreed on real data.
unit_dimensions
utils.units.unit_dimensions(unit)Base-dimension exponents of unit as {base unit name: Fraction}.
The SI base dimensions of ISO 80000-1, straight from QUDT’s dimension vector: mV is {kilogram: 1, meter: 2, second: -3, ampere: -1}. An empty mapping is dimensionless; None means uncurated, which is not the same claim.
unit_expression
utils.units.unit_expression(unit)unit as a SymPy expression over SI base quantities, or None if uncurated.
Q = {Q}·[Q]: the numeric multiplier times the base-unit product, so mV is kilogram*meter**2/(1000*ampere*second**3). Built from the vendored multiplier and dimension vector rather than from a name, because no naming convention resolves mm_per_ms — sympy.physics.units has no such quantity, and looking one up by name yields a free symbol that compares equal to nothing and raises nothing. Deriving it also keeps the expression and the dimension vector beside it from ever disagreeing.
Affine units are refused: degC carries a conversion offset, so it is not a multiple of kelvin and no single expression states it.
unit_facts
utils.units.unit_facts(unit)The vendored QUDT record for unit, or None if it is not curated.
None covers both an unknown spelling and a value carried in the enum without unit facts (per_unit), because neither can be reasoned about dimensionally — the caller’s fallback is the same for both.
unit_has_time_dimension
utils.units.unit_has_time_dimension(unit)Return True if the unit carries a time component (T or T⁻¹).
This is the key signal for NeuroML LEMS export: if any parameter in the RHS equation has a time dimension, the equation already carries time normalisation and / SEC is not needed.
unit_multiplier
utils.units.unit_multiplier(unit)The exact Fraction scaling unit onto SI base units, or None if uncurated.
Exact because ratios of it are the thing being checked: mm/ms over m/s is Fraction(1), where the float route gives 0.9999999999999999 and a dimensional check that should read “identical” reads “off by 1e-16”.
unit_named
utils.units.unit_named(expression)The one curated unit whose expression is exactly expression, or None.
The inverse of unit_expression, used to give a derived unit back its ordinary name: propagation produces kilogram*meter**2/(1000*ampere*second**3), which is mV and reads far better said that way. Exact because the expressions are built from Fraction multipliers, so mm/ms and m/s are the same key rather than two that differ by 1e-16.
None when several units share the expression, which is not a gap in the vocabulary but a limit on what dimensional analysis can tell you: Hz, per_s and rad_per_s are all exactly 1/second, as are dimensionless, arbitrary_unit and rad all exactly 1. Five such groups exist among the curated units. Naming a derived quantity Hz would assert it is a frequency on evidence that says only “per second”, so the base expression is printed instead — a weaker claim, and the true one.
unit_to_latex
utils.units.unit_to_latex(unit)Return a LaTeX string for the unit, suitable for wrapping in $...$.
Converts enum values like per_ms → \\mathrm{ms}^{-1}, rad_per_ms → \\mathrm{rad}\\,\\mathrm{ms}^{-1}. Returns an empty string for dimensionless / unknown units.
unit_to_lems_dimension
utils.units.unit_to_lems_dimension(unit)Return the LEMS dimension name for a UnitEnum value (or string).
Read from the LEMS entry in the software database, which is where a claim about what LEMS calls things belongs. Units LEMS has no dimension for — including every one it simply has no name for — come back "none", its own spelling of dimensionless.
unit_to_lems_symbol
utils.units.unit_to_lems_symbol(unit)Return the LEMS unit symbol string for appending to numeric values.
For dimensioned parameters (e.g. pF, nS, mV), returns the matching LEMS unit symbol. For dimensionless or unknown units, returns "".
unit_to_si_factor
utils.units.unit_to_si_factor(unit)Return the multiplicative factor to convert from unit to SI base units.
Read from the vendored QUDT record, not from a local table. The table this replaced held 19 of the 62 curated units and returned 1.0 for the rest, so mm converted as though it were metres — silently, which is how it survived.
unit_to_si_factor(“mV”) 0.001 unit_to_si_factor(“ms”) 0.001 unit_to_si_factor(None) 1.0
unit_to_symbol
utils.units.unit_to_symbol(unit)Return the conventional display symbol for a UnitEnum value.
For simple abbreviations (ms, mV, nA), the enum value IS the symbol. For compound forms (per_ms, mV_per_ms), returns conventional notation.
unit_to_symbol(“ms”) ‘ms’ unit_to_symbol(“per_ms”) ‘1/ms’ unit_to_symbol(None) ’’