The Model API¶
The main construct in cellmlmanip is a cellmlmanip.model.Model
.
This represents a flattened CellML model and metadata about its variables.
- class cellmlmanip.model.Model(name, cmeta_id=None, unit_store=None)[source]¶
Bases:
object
A componentless representation of a CellML model, containing a list of equations, units, and RDF metadata about variables used in those equations.
The main parts of a Model are 1. a list of sympy equation objects; 2. a collection of named units; and 3. an RDF graph that stores further meta data about the model.
Equations are stored as
sympy.Eq
objects, but with the caveat that all variables and numbers must be specified using thesympy.Dummy
objects returned byadd_variable()
andcreate_quantity()
.Units are handled using the
units
property of a model, which is an instance ofcellmlmanip.units.UnitStore
.RDF meta data can be attached to either the model itself or to model variables, via the CellML
cmeta:id
attribute. Cmeta ids set on any other parts of CellML models are ignored.Cellmlmanip does not support algebraic models: the left-hand side every equation in the model must be a variable or a derivative.
- Parameters:
name – the name of the model e.g. from
<model name="">
.cmeta_id – An optional cmeta id, e.g. from
<model cmeta:id="">
.unit_store – Optional
cellmlmanip.units.UnitStore
instance; if given the model will share the underlying registry so that conversions between model units and those from the provided store work.
- get_state_variables(sort=True)[source]¶
Returns a list of state variables found in the given model graph (ordered by appearance in the CellML document).
- Parameters:
sort – indicates whether the list is sorted by appearance in the CellML document.
- get_derivatives(sort=True)[source]¶
Returns a list of
sympy.Derivative
objects found as LHS in the given model graph.- Parameters:
sort – indicates whether the list is sorted by appearance in the CellML document.
- get_derived_quantities(sort=True)[source]¶
Returns a list of derived quantities found in the given model graph.
A derived quantity is any variable that is not a state variable, free variable, or parameter/constant. :param sort: indicates whether the list is sorted by appearance in the CellML document.
- get_display_name(var, ontology=None, exclude_terms=None)[source]¶
Return a display name for the given variable.
Looks for an annotation in the ontology first (or the local name from any annotation if no ontology is specified), skipping any terms in exclude_tags, then
cmeta:id
if present, or the variable’sname
attribute if not.Dollar symbols in the name are replaced by a double underscore.
- Parameters:
var – the variable for which to get the display name.
ontology – the base URL of an ontology if only annotations within that ontology should be considered
exclude_terms – a collection of terms that should be skipped when searching the ontology for a variable name.
- Returns:
the display name for the variable according to the algorithm above
- is_state(variable)[source]¶
Checks if
variable
is a state variable (i.e. if it’s defined by an ODE).
- is_constant(variable)[source]¶
Determine whether
variable
is a constant.This is calculated by looking at the RHS of the defining equation and checking it has no variable references.
- get_variable_by_cmeta_id(cmeta_id)[source]¶
Searches the model and returns the variable with the given
cmeta id
.To get variables from e.g. an oxmeta ontology term, use
get_variable_by_ontology_term()
.- Parameters:
cmeta_id – Either a string id or
rdflib.URIRef
instance.- Returns:
A
Variable
object
- get_variable_by_ontology_term(term)[source]¶
Searches the RDF graph for a variable annotated with the given
term
and returns it.Specifically, this method searches for a unique variable annotated with predicate
http://biomodels.net/biology-qualifiers/is
and the object specified byterm
.Will raise a
KeyError
if no variable with the given annotation is found, and aValueError
if more than one variable with the given annotation is found.- Parameters:
term – anything suitable as an input to
cellmlmanip.rdf.create_rdf_node()
; typically either an RDF node already, or a tuple(namespace_uri, local_name)
.
- get_variables_by_rdf(predicate, object_=None, sort=True)[source]¶
Find variables annotated with the given predicate and object (e.g.
is oxmeta:time
) in our RDF graph.Both
predicate
andobject_
(if given) must be suitable as an input tocellmlmanip.rdf.create_rdf_node()
; typically either(namespace, local_name)
tuples or string literals.- Parameters:
sort – indicates whether the list is sorted by appearance in the CellML document.
- Returns:
the associated variables sorted in document order
- get_rdf_value(subject, predicate)[source]¶
Get the value of an RDF object connected to
subject
bypredicate
.Note: expects exactly one triple to match and the result to be a literal.
- Parameters:
subject – the object of the triple returned
predicate – the object of the triple returned
- Returns:
a string
- get_rdf_annotations(subject=None, predicate=None, object_=None)[source]¶
Searches the RDF graph and returns triples matching the given parameters.
- Parameters:
subject – the subject of the triples returned
predicate – the predicate of the triples returned
object – the object of the triples returned
Each of
subject
,predicate
andobject_
are optional; ifNone
then any triple matches. If all areNone
, then all triples are returned.The arguments can be anything valid as input to
cellmlmanip.rdf.create_rdf_node()
, typically a (namespace URI, local name) pair, a string, orNone
.
- get_ontology_terms_by_variable(variable, namespace_uri=None)[source]¶
Returns all ontology terms linked to the given
variable
via thehttp://biomodels.net/biology-qualifiers/is
predicate.- Parameters:
variable – The variable to search for (as a
Variable
object).namespace_uri – An optional namespace URI. If given, only terms within the given namespace will be returned.
- Returns:
A list of term local names.
- has_ontology_annotation(variable, namespace_uri=None)[source]¶
Checks that there is at least one result for
Model.get_ontology_terms_by_variable()
with the given arguments.
- has_cmeta_id(cmeta_id)[source]¶
Returns
True
only if the givencmeta_id
exists in this model.Note that only cmeta ids on variables or the model itself are checked and supported.
- get_definition(variable)[source]¶
Get the equation (if any) defining the given variable.
- Parameters:
variable – The variable to look up (as a
Variable
). If this appears as the LHS of a straight assignment, or the state variable in an ODE, the corresponding equation will be returned.- Returns:
A Sympy equation, or
None
if the variable is not defined by an equation.
- get_value(variable)[source]¶
Returns the evaluated value of the given variable, as a float.
For state variables, this returns the initial value. For variables that depend on other variables this recursively evaluates any dependencies (again at the initial state). Zero is returned for the free variable (as identified by
get_free_variable()
); trying to evaluate other variables without a definition will result in aValueError
.
- get_equations_for(variables, recurse=True, strip_units=True)[source]¶
Get all equations for a given collection of variables.
Results are sorted first by dependencies, then by variable name.
- Parameters:
variables – The variables to get the equations for (as
Variable
objects).recurse – Indicates whether to recurse the equation graph, or to return only the top level equations.
strip_units – If
True
, allQuantity
objects representing number with units will be replaced with ordinary sympy number objects. Note that if this is done then the equations returned may not be found in the model, so you should not try calling e.g.remove_equation()
with them.
- property graph¶
A
networkx.DiGraph
containing the model equations.
- property graph_with_sympy_numbers¶
A
networkx.DiGraph
containing the model equations, but with numbers represented assympy.Number
objects instead ofQuantity
objects.
- get_unique_name(name)[source]¶
Creates and returns a unique variable name, not used in the model.
- Parameters:
name (str) – Suggested unique name.
- Return str:
Guaranteed unique name.
- add_variable(name, units, initial_value=None, public_interface=None, private_interface=None, cmeta_id=None)[source]¶
Adds a variable to the model and returns a
Variable
to represent it in sympy expressions.- Parameters:
name – A string name.
units – A string unit name or a
Unit
object.initial_value – An optional initial value.
public_interface – An optional public interface specifier (only required when parsing CellML).
private_interface – An optional private interface specifier (only required when parsing CellML).
cmeta_id – An optional string specifying a cmeta id
- Raises:
ValueError – If a variable with that name already exists, or the given cmeta id is already taken.
- Returns:
A
Variable
object.
- remove_variable(variable)[source]¶
Remove a variable and its defining equation from the model.
This will remove the equation either that defines
variable
directly, or if it is a state variable the corresponding ODE. All annotations about this variable are also removed from the RDF graph.- Parameters:
variable (Variable) – the variable to remove
- add_equation(equation, check_duplicates=True)[source]¶
Adds an equation to this model.
The left-hand side (LHS) of the equation must be either a variable (as a
Variable
) or a derivative (as asympy.Derivative
).All numbers and variables used in the equation must have been obtained from this model, e.g. via
create_quantity()
,add_variable()
, orget_variable_by_ontology_term()
.- Parameters:
equation – A
sympy.Eq
object.check_duplicates – whether to check that the equation’s LHS is not already defined
- remove_equation(equation)[source]¶
Removes an equation from the model.
- Parameters:
equation – The equation to remove.
- create_quantity(value, units)[source]¶
Creates and returns a
Quantity
to represent a number with units in Sympy expressions.Use this method rather than creating quantities directly to ensure their units are compatible with those used by the model, so unit conversion etc. works.
- add_cmeta_id(variable)[source]¶
Adds a (unique) cmeta id to the given variable.
If the variable already has a cmeta id no action is performed.
- Parameters:
variable – A
Variable
.
- transfer_cmeta_id(source, target)[source]¶
Removes the
cmeta_id
from the variablesource
and adds it totarget
.Raises a
ValueError
ifsource
doesn’t have a cmeta id, or iftarget
already has a cmeta id.
- convert_variable(original_variable, units, direction, move_annotations=True)[source]¶
Ensures the model contains a variable representing
original_variable
in the specifiedunits
.If the variable is already in the required units, nothing happens, and
original_variable
is returned.If the variable’s units can be converted to the new
units
, a new variable will created in these units, and thecmeta:id
attribute oforiginal_variable
will be moved to the new variable, so that all annotations are transferred to the new variable (unlessmove_annotations
is given asFalse
).The
direction
argument specifies how information flows between the new variable and the original, and hence what new equation(s) will be added to the model to perform the conversion. Ifdirection
isDataDirectionFlow.INPUT
, then the original variable takes its value from the newly added variable; if it isDataDirectionFlow.OUTPUT
then the opposite happens. If the direction isINPUT
then any initial value will be moved to the new variable (and converted appropriately).For example, a model:
var time :: ms {cmeta_id: time} var sv1 :: mV {cmeta_id: sv11, init: 2} ode(sv1, time) = 1 :: mV_per_ms
transformed with:
convert_variable(sv11, volt, DataDirectionFlow.OUTPUT)
becomes:
var time :: ms {cmeta_id: time} var sv1 :: mV {init: 2} var sv1_converted :: volt {cmeta_id: sv11} ode(sv1, time) = 1 :: mV_per_ms sv1_converted = sv1 * 0.001 :: V_per_mV
If the information flow is reversed, i.e. with:
convert_variable(sv11, volt, DataDirectionFlow.INPUT)
then the model becomes:
var time :: ms {cmeta_id: time} var sv1 :: mV var sv1_converted :: volt {cmeta_id: sv11, init: 0.002} ode(sv1_converted, time) = (1 :: mV_per_ms) * 0.001 :: V_per_mV sv1 = sv1_converted * 1000 :: mV_per_V
Converting time as an input requires further processing, because every ODE needs adapting. With:
convert_variable(time, second, DataDirectionFlow.INPUT)
the model becomes:
var time :: ms var time_converted :: s {cmeta_id: time} var sv1 :: mV {cmeta_id: sv11, init: 2} var sv1_orig_deriv :: mV_per_ms time = 1000 :: ms_per_s * time_converted sv1_orig_deriv = 1 :: mV_per_ms ode(sv1, time_converted) = 1000 :: ms_per_s * sv1_orig_deriv
- Parameters:
original_variable – the
Variable
object representing the variable in the model to be convertedunits – a
Unit
object representing the units to convert variable to (note if variable is already in these units, model remains unchanged and the original variable is returned)direction – either DataDirectionFlow.INPUT: the variable to be changed is an input and all affected equations will be adjusted; or DataDirectionFlow.OUTPUT: the variable to be changed is an output, equations are unaffected apart from converting the actual output
move_annotations – whether to point metadata annotations at the converted variable instead of the original
- Returns:
new variable with desired units, or original unchanged if conversion was not necessary
- Raises:
DimensionalityError – if the unit conversion is impossible
- find_variables_and_derivatives(expressions)[source]¶
Returns a set containing all variables and derivatives referenced in a list of expressions.
Note that we can’t just use
.atoms(Variable, sympy.Derivative)
for this, because it will return the state and free variables from inside derivatives, which is not what we want.- Parameters:
expressions – an iterable of expressions to get variables for.
- Returns:
a set of variables and derivatives, as
Variable
andsympy.Derivative
objects respectively.
- remove_fixable_singularities(V, exclude={})[source]¶
Removes removable singularities from the model equations and replaces these with a piecewise.
The process looks for equations of any of the following forms, where U is a function of V: - U / (exp(U) - 1.0) - U / (1.0 - exp(U)) - (exp(U) - 1.0) / U - (1.0 - exp(U)) / U It replaces these with a piecewise 1e-7 either side of U==0 drawing a stright line in the region. For example (V + 5)/(exp(V + 5) - 1) becomes ((fabs(-V - 5.0000000000000000) < fabs(-4.9999999000000000 / 2 - -5.0000001000000000 / 2)) ? -0.494049243462503*V - 1.4702462167574 : ((5.0 + V) / (-1.0 + exp(5.0 + V))))
see [Johnstone, R. H. (2018). Uncertainty characterisation in action potential modelling for cardiac drug safety. University of Oxford.](https://ora.ox.ac.uk/objects/uuid:0a28829c-828d-4641-bfb0-11193ef47195)
- Parameters:
exclude – set of variables which will not be substituted in the evaluation.
This ensures their defining equations will remain.
- class cellmlmanip.model.Quantity(value, *args, **kwargs)[source]¶
Bases:
Dummy
Used to represent a number with a unit, inside a Sympy expression.
Unlike sympy expressions, this number type will never be removed in simplify operations etc.
Quantities should never be created directly, but always via
Model.create_quantity()
.Assumes the value is real.
To get the actual value as a float or string, use
float(dummy)
orstr(dummy)
respectively. You can also usequantity.evalf()
to get the value as asympy.Float
.
- class cellmlmanip.model.Variable(*args, **kwargs)[source]¶
Bases:
Dummy
Used to represent a variable (with meta data) in a Sympy expression.
Variables should never be created directly, but always via
Model.add_variable()
.For the constructor arguments, see
Model.add_variable()
.Assumes the value is real.
- property rdf_identity¶
The RDF identity for this variable (will be
None
unless the variable has a cmeta id).
- property cmeta_id¶
Provides read-only access to the cmeta id.
- class cellmlmanip.model.DataDirectionFlow(value)[source]¶
Bases:
Enum
Direction of data flow for converting units.
- class cellmlmanip.model.VariableType(value)[source]¶
Bases:
Enum
Classification of variables according to their role in the model’s mathematics.
UNKNOWN
not yet classified
STATE
the dependent variable in an ODE
FREE
the independent variable in an ODE
PARAMETER
defined directly as a constant number (note that this does not include variables defined by an equation that evaluates as constant)
COMPUTED
defined by any other equation
- cellmlmanip.rdf.create_rdf_node(node_content)[source]¶
Creates and returns an RDF node.
- Parameters:
node_content – the content for the node.
The
node_content
, if given, must either be ardflib.term.Node
instance, a tuple(namespace_uri, local_name)
, or a string, in which case it is interpreted as either a URI ref if it starts with # otherwise a literal RDF node.node_content
may also beNone
to returnNone
, allowing easy handling of wildcard options to queries.