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:
objectCreates and stores units, and has functions for unit conversion.
Within a UnitStore
store, units are represented asstore.Unitobjects, while numbers with units are represented asstore.Quantityobjects. Both classes are inherited from thepintpackage.Each UnitStore has its own unique namespace for storing units.
By default, each UnitStore maintains an internal
pint.UnitRegistryand 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
ato 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
cto be converted to units froma.- Parameters:
store – An existing
UnitStoreto share a unit registry with.
- class Quantity¶
A
pint.Quantityclass tied to this unit store.
- add_unit(name, expression)[source]¶
Adds a unit called
nameto 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
Unitobject.
- format(unit, base_units=False)[source]¶
Returns a string representation of a unit.
- Parameters:
unit – The
Unitobject to format.base_units – If this optional argument is set to
Truethe 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
Unita Sympy expression is in; but will also attempt to fix inconsistencies inexprand return an updated expression if needed.- Parameters:
expr – the Sympy expression whose units to evaluate.
- Returns:
A tuple
(units, new_expr)whereunitsis the calculatedUnitobject, andnew_expris eitherexpror 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_unitsare given asNone, this method will only convert to ensure thatexpris 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 theEqexpression is passed in asexprandto_unitsis 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
Unitobject, orNoneif we don’t care or for converting an assignment expression.
- Returns:
a Sympy expression in the desired units; the input
exprif 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:
objectEvaluates 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:
ExceptionBase 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:
UnitErrorInvalid 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:
UnitErrorInvalid 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:
UnitErrorInvalid 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:
UnitErrorInvalid 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:
UnitErrorInvalid 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:
UnitErrorRepresents 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