Units¶
Units are stored in a cellmlmanip.units.UnitStore
.
When a model is parsed, a UnitStore
is created automatically.
The cellmlmanip.units
module provides unit handling for CellML models, using the
Pint unit library.
- class cellmlmanip.units.UnitStore(store=None)[source]¶
Bases:
object
Creates and stores units, and has functions for unit conversion.
Within a UnitStore
store
, units are represented asstore.Unit
objects, while numbers with units are represented asstore.Quantity
objects. Both classes are inherited from thepint
package.Each UnitStore has its own unique namespace for storing units.
By default, each UnitStore maintains an internal
pint.UnitRegistry
and units from different stores cannot be compared or interact with each other. To allow comparison and conversion between unit stores, an existing UnitStore can be passed in at construction time, so that the underlying registry will be shared. (This will allow units from different stores to interact, but the unit stores will maintain independent namespaces).For example:
a = UnitStore() b = UnitStore()
creates two separated unit stores, each with their own namespace, and without the option to compare units from
a
to units fromb
.But:
a = UnitStore() b = UnitStore(a) c = UnitStore(b)
creates three unit stores, each with their own namespace, but with a single underlying registry for all three stores, allowing e.g. units from
c
to be converted to units froma
.- Parameters:
store – An existing
UnitStore
to share a unit registry with.
- class Quantity¶
A
pint.Quantity
class tied to this unit store.
- add_unit(name, expression)[source]¶
Adds a unit called
name
to the unit store, as defined by the stringexpression
.For example:
add_unit('mm', 'meter / 1000')
- Parameters:
name – A string name. Names must be unique and cannot overlap with CellML predefined units.
expression – An expression to define the new unit.
- Returns:
The newly created
Unit
object.
- format(unit, base_units=False)[source]¶
Returns a string representation of a unit.
- Parameters:
unit – The
Unit
object to format.base_units – If this optional argument is set to
True
the string will show the base units expansion of the given unit.
- get_conversion_factor(from_unit, to_unit)[source]¶
Returns the magnitude multiplier required to convert a unit to the specified unit.
- add_conversion_rule(from_unit, to_unit, rule)[source]¶
Adds a complex conversion rule for converting between incompatible units.
For example:
units = UnitStore() uA = units.add_unit('uA', 'ampere * 1e-6') pA = units.add_unit('pA', 'ampere * 1e-12') uF = units.add_unit('uF', 'farad * 1e-6') pF = units.add_unit('pF', 'farad * 1e-12') cm2 = units.add_unit('cm2', 'centimetre ** 2') uA_per_cm2 = uA_per_cm2 = units.add_unit('uA_per_cm2', 'uA / cm2') uF_per_cm2 = units.add_unit('uF_per_cm2', 'uF / cm2') A_per_F = units.add_unit('A_per_F', 'ampere / farad') Cm = units.Quantity(12, pF) Cs = units.Quantity(1.1, uF_per_cm2) units.add_conversion_rule(uA, uA_per_cm2, lambda ureg, rhs: rhs * Cs / Cm) units.add_conversion_rule(uA_per_cm2, A_per_F, lambda ureg, rhs: rhs / Cs) # Test print(units.convert(units.Quantity(1, pA), A_per_F)) print(units.convert(units.Quantity(1, uA_per_cm2), A_per_F))
- Parameters:
Note that the function does not need to convert exactly to/from the specified units, just to the correct dimensions. Pint will scale appropriate once that is done.
- evaluate_units_and_fix(expr)[source]¶
Evaluates and returns the
Unit
a Sympy expression is in; but will also attempt to fix inconsistencies inexpr
and return an updated expression if needed.- Parameters:
expr – the Sympy expression whose units to evaluate.
- Returns:
A tuple
(units, new_expr)
whereunits
is the calculatedUnit
object, andnew_expr
is eitherexpr
or a copy made internally consistent.- Raises:
UnitError – if there are unfixable unit errors when evaluating the expression’s units.
- convert_expression_recursively(expr, to_units)[source]¶
Generate a version of the given expression in the requested units.
Rather than assuming the expression is internally consistent (and hence just wrapping in a conversion factor) this will recursively traverse the expression tree and convert at each level as needed. Hence if the operands of internal expressions are in dimensionally consistent but not equal units, conversions will be applied as needed.
If the
to_units
are given asNone
, this method will only convert to ensure thatexpr
is internally consistent. As a result, this method is suitable for use converting the RHS of assignment equations to the units desired by the LHS, if theEq
expression is passed in asexpr
andto_units
is given asNone
.The conversion strategy for each (sub-)expression depends on the operator:
for relational operators, all operands are converted to the units of the first operand
for Mul the operands can be in any units, and we convert the result if needed
for Add all operands are converted to the desired units (or the units of the first operand if no desired units are given)
for Pow the exponent must be dimensionless while the operand can be in any units, and we convert the result if needed
for trig functions, exp, log, etc. the operands have to have dimensionless units
for piecewise, the conditions must be dimensionless, and the pieces are set to the desired units (or the units of the first piece)
for derivatives, numbers, variables, etc. we just convert to the desired units
- Parameters:
expr – the Sympy expression to convert
to_units – the desired units of the expression as a
Unit
object, orNone
if we don’t care or for converting an assignment expression.
- Returns:
a Sympy expression in the desired units; the input
expr
if no conversion was needed.- Raises:
UnitError – if conversion is not possible, using a suitable subclass depending on the exact reason
- class cellmlmanip.units.UnitCalculator(unit_store)[source]¶
Bases:
object
Evaluates a Sympy expression to determine its units.
Note: only supports a subset of Sympy math.
- Parameters:
unit_store – A
UnitStore
.
- traverse(expr)[source]¶
Descends the Sympy expression and performs Pint unit arithmetic on sub-expressions.
NOTE: Sympy will raise exceptions if the expression is badly formed.
- Parameters:
expr – a Sympy expression
- Returns:
the quantity (i.e. magnitude(expression) * unit) of the expression
- Raises:
KeyError – if variable not found in metadata
UnexpectedMathUnitsError – if math is not supported
BooleanUnitsError – if math returns booleans
InputArgumentsMustBeDimensionlessError – if input arguments should be dimensionless
InputArgumentsInvalidUnitsError – if input arguments should have same units
InputArgumentMustBeNumberError – if one of input arguments should be a number
- convert_expression_recursively(expr, to_units)[source]¶
Helper method for
UnitStore.convert_expression_recursively()
which does the heavy lifting.- Returns:
a tuple
(new_expr, was_converted, actual_units)
- exception cellmlmanip.units.UnitError[source]¶
Bases:
Exception
Base class for errors relating to calculating units.
- add_context(expression, message)[source]¶
Add extra context to the error message.
Will append
('Context: ' + message).format(expression)
to the error message.- Parameters:
expression – the wider expression within which a unit calculation error occurred
message – further details explaining the context of the error
- exception cellmlmanip.units.UnexpectedMathUnitsError(expression, message='')[source]¶
Bases:
UnitError
Invalid units error thrown when math encountered in an expression is outside the subset of MathML expected.
- Parameters:
expression – input expression in which the error occurred
message – optional message with further detail
- exception cellmlmanip.units.InputArgumentsInvalidUnitsError(expression)[source]¶
Bases:
UnitError
Invalid units error thrown when the arguments to a function have incorrect units.
For example it is incorrect to add 1 [meter] to 2 [seconds].
- Parameters:
expression – input expression in which the error occurred
- exception cellmlmanip.units.InputArgumentsMustBeDimensionlessError(expression, position='')[source]¶
Bases:
UnitError
Invalid units error thrown when the arguments to a function have units when the function expects the arguments to be dimensionless.
For example it is incorrect to use a sine function on an argument with units.
- Parameters:
expression – input expression in which the error occurred
- exception cellmlmanip.units.InputArgumentMustBeNumberError(expression, position)[source]¶
Bases:
UnitError
Invalid unit error thrown when the input argument should be a number.
For example root(x, y) is invalid unless y is a dimensionless number.
- Parameters:
expression – input expression in which the error occurred
position – the position of the argument with error i.e. first/second
- exception cellmlmanip.units.BooleanUnitsError(expression)[source]¶
Bases:
UnitError
Invalid units error when being asked for units of an expression that will return a boolean.
For example it is incorrect to use the expression 1 [meter] > 0.5 [seconds].
- Parameters:
expression – input expression in which the error occurred
- exception cellmlmanip.units.UnitConversionError(expression, from_units, to_units)[source]¶
Bases:
UnitError
Represents failure to convert between incompatible units.
- Parameters:
expression – the Sympy expression in which the error occurred
from_unit – the units the expression is in
to_unit – the units we tried to convert to