Informative CellML 2.0 Specification¶
Definitions¶
Terminology¶
The keywords “MUST”, “MUST NOT”, “SHALL”, “SHALL NOT”, and “MAY” in this document are to be interpreted as described in RFC 2119 [1].
The key phrase “information item”, as well as any specific type of information item such as an “element information item”, are to be interpreted as described in XML Information Set [2].
CellML infoset: An XML information set containing a hierarchy of information items conforming to the rules described in this document. In this specification, such infosets are assumed to be CellML 2.0 infosets.
CellML model: A mathematical model represented by a hierarchy of one or more CellML infosets, according to the rules described in this document. In this specification, the topmost CellML infoset in a hierarchy is referred to as the top-level CellML infoset.
Namespace: An XML namespace, as defined in Namespaces in XML 1.1 [3].
CellML namespace: The CellML 2.0 namespace.
CellML 2.0 namespace: The namespace http://www.cellml.org/cellml/2.0#.
MathML namespace: The namespace http://www.w3.org/1998/Math/MathML.
CellML information item: Any information item in the CellML namespace.
Basic Latin alphabetical character: A Unicode [4] character in the range U+0041 to U+005A or in the range U+0061 to U+007A.
Digit: A Unicode character in the range U+0030 to U+0039.
Basic Latin alphanumerical character: A Unicode character which is either a Basic Latin alphabetical character or a digit.
Basic Latin underscore: The Unicode character U+005F.
Basic Latin plus: The Unicode character U+002B.
Basic Latin minus: The Unicode character U+002D.
Basic Latin full stop: The Unicode character U+002E.
Whitespace character: Any one of the Unicode characters U+0009, U+000A, U+000D, or U+0020.
See more
Namespaces
Namespaces are a way of making sure that names and definitions are interpreted within the right frame of reference.
In CellML, two namespaces are used.
These are the CellML namespace itself (which helps to define the units
elements as distinct from the XML default units system) and the MathML namespace used to interpret the math
elements.
For more information on namespaces in general, please refer to the W3 schools namespace page, or for the MathML namespace please refer to the W3 MathML namespace page.
Unicode, Basic Latin alphabetical characters, and digits
The Unicode project is an attempt to codify all of the symbols - alphabets, writings, even emojis - of all the languages of the world so that they can be interchangeable and interpreted by computers. Since computers understand numbers rather than symbols, each character in each language is given a unique numerical code. The codes themselves are arranged into blocks representing sets of characters, and the Basic Latin block is one of these. It contains, amongst other things, the upper and lowercase alphabet without decoration:
These characters are referred to in CellML as the “Basic Latin alphabetical characters”.
The “digits” are the Unicode characters:
Together with the Basic Latin alphabetical characters, they form the “Basic Latin alphanumerical characters”.
In addition, CellML recognises four special characters:
+
the plus sign (U+002B),-
the minus sign (U+002D),.
the full stop or decimal point (U+002E),_
the underscore (U+005F),
and the following whitespace characters:
These symbols and character sets will be used throughout the CellML definition to define allowed content of attributes and elements.
CellML information sets¶
CellML and XML¶
Every CellML infoset SHALL be represented in an XML information set which conforms with the well-formedness requirements of XML 1.1 [5].
In this document, the remaining provisions relating to CellML infosets SHALL be interpreted as additional constraints on the XML information set represented by a CellML infoset.
Specific information items¶
For the purposes of this specification, a specific information item is one of the following (see https://www.w3.org/TR/2004/REC-xml-infoset-20040204/ for definitions):
A document information item;
An element information item;
An attribute information item;
A processing instruction information item;
An unexpanded entity reference information item;
A document type declaration information item;
An unparsed entity information item; or
A notational information item.
Specific information items MUST NOT appear in a CellML infoset except where explicitly allowed by this specification, or where allowed by a normative specification referenced by this specification.
The order in which specific information items appear, as children of an element information item defined in this specification, SHALL NOT affect the semantic interpretation of the CellML model.
See more
Specific information items
There are different kinds of information stored in XML elements.
In the example below, the food_ideas
element has:
title
,instructions
,ingredient
have text content (note that numbers like 1.0 are treated as text),ingredients
andfood_ideas
have element contents, because they have child elements inside them,category
is an attribute of therecipe
element, andname
andunits
are attributes of theingredient
element, andthe note within
<!-- ... -->
comment tags is of an unparsed type and is ignored.
<food_ideas>
<recipe category="easy">
<title>Three ingredient scones</title>
<!-- These are so easy ... and if you're clever you'll save a little cream for whipping on the top! -->
<ingredients>
<ingredient name="cream" units="cup">1.0</ingredient>
<ingredient name="lemonade" units="cup">1</ingredient>
<ingredient name="selfraising_flour" units="cup">4</ingredient>
</ingredients>
<instructions>
Mix them all together using your hands.
You can use extra flour if you need to.
Bake at 220C for about 12 minutes or until golden.
</instructions>
</recipe>
</food_ideas>
Using CellML this could be written:
<model name="recipes">
<units name="cup">
<unit units="litre" prefix="milli" multiplier="250.0" />
</units>
<component name="Three_ingredient_scones">
<!-- Sigh ... if only it were possible for my computer to make me tea ... -->
<variable name="cream" cellml:units="cup" initial_value="1" />
<variable name="lemonade" cellml:units="cup" initial_value="1" />
<variable name="selfraising_flour" cellml:units="cup" initial_value="5" />
<variable name="mixture" cellml:units="cup" />
<math>
<apply><eq/>
<ci>mixture</ci>
<apply><plus/>
<ci>cream</ci>
<ci>lemonade</ci>
<ci>selfraising_flour</ci>
</apply>
</apply>
</math>
</component>
<!-- BUT THIS IS NOT VALID! -->
<extra type="Danger_Will_Robinson">
Even though this looks like a valid XML text block, it's not allowed here. Only those
elements which are explicitly specified as types of children are allowed!
</extra>
</model>
Non-specific information items¶
For the purposes of this specification, a non-specific information item is one of the following (see https://www.w3.org/TR/2004/REC-xml-infoset-20040204/ for definitions):
A comment information item;
A namespace information item; or
A character information item.
An element information item in the CellML namespace MUST NOT contain any character information items, except for whitespace characters.
See more
<!-- This is not valid! -->
<model name="myInvalidCellML">
... because it has stuff here that shouldn't be here.
</model>
Two CellML infosets SHALL be deemed semantically equivalent if one can be transformed into the other by making zero or more of the following changes:
Adding, removing, and/or modifying comment information items.
Changing (inserting, removing, and/or modifying) one or more namespace information items, and/or modifying the prefix of one or more information items, without changing the namespace that any information item is in.
The following paragraph applies to character information items which are the direct child of an element information item in the CellML namespace, or in the MathML namespace: inserting or removing character information items that consist entirely of whitespace characters, changing the number of whitespace characters in such an information item, or changing the number of whitespace characters at the beginning or end of any character information item.
See more
Semantic equivalence
The example below is identical to that in the previous “See more” block because:
newlines, tabs, whitespace do not affect equivalence (except as part of text or attribute content),
the order of element definition does not affect equivalence,
the order of attribute definition does not affect equivalence, and
comments do not affect equivalence.
<model name="recipes">
<component name="Three_ingredient_scones">
<!--
Comments are ignored ...
so here's a really long one about how much I now
feel like yummy scones and jam and cream and tea ...
-->
<!-- The order of child elements is ignored -->
<math>
<apply><eq/>
<ci>mixture</ci>
<apply><plus/>
<ci>cream</ci>
<ci>lemonade</ci>
<ci>selfraising_flour</ci>
</apply>
</apply>
</math>
<!-- Whitespace (including tab, new line, and space) between attributes is ignored. -->
<variable
name="selfraising_flour"
cellml:units="cup"
/>
<variable name="cream" cellml:units="cup" />
<!-- Whitespace (including tab, new line, and space) between elements is ignored. -->
<variable cellml:units="dimensionless" name="mixture" /><variable name="lemonade" cellml:units="cup" />
</component>
<units name="cup">
<!-- The order of attributes within an element is ignored. -->
<unit multiplier="250.0" prefix="milli" units="litre" />
</units>
</model>
Use of namespaces¶
Element information items in a CellML infoset MUST belong to one of the following namespaces, unless explicitly indicated otherwise:
The CellML namespace; or
The MathML namespace.
Attribute information items in a CellML element MUST NOT be prefixed with a namespace, unless explicitly indicated otherwise.
XML ID Attributes¶
Any element information item in the CellML namespace MAY contain an attribute with local name
id.
This attribute SHALL be treated as having attribute type ID, as defined in Section 3.3.1 of XML 1.1 [5].
See more
Understanding element IDs
In order to understand how the XML id
attribute is used in CellML models, we need to understand four things.
Firstly, in CellML the elements are identified by uniqueness over the model scope of their name
attribute, their type (eg: variable
), and in some cases, by their parent element too.
Secondly, the CellML model
might exist over several different documents, and make use of import
functionality to connect these documents into one model.
Thirdly, the uniqueness of the XML id
attribute value extends only to the document scope, not the CellML model scope.
Finally, there are aspects of the written XML which do not contribute to the conceptual model as represented by the CellML; simple examples are things like whitespace between elements, comments, quotation and angle bracket markers.
These are all parts of the written language which guide interpretation into the conceptual model.
The id
attribute is likewise an XML attribute which falls into the same category: it may be read when a document is parsed, but as it doesn’t form a part of any CellML element, it doesn’t exist in the constructed conceptual representation.
Having said this, the syntax of CellML is a subset of XML (as specified in 1.2 CellML information sets), so the rules of XML id
attributes must be followed, where present.
Consider the example below.
# In the document "BreakfastMenu.cellml".
# All id attributes are unique within this document.
model: name = "BreakfastOfChampions", id = "b"
├─ component: name = "Protein", id = "p"
├─ component: name = "Carbohydrates", id = "c" <╴╴╴╴╴╴╴╴╴┐
└─ component: name = "FunStuff", id = "f" ╷
└─ variable: name = "FunStuff", id = "fs" ╷
╷
Valid: A CellML component named "Porridge" is
imported, but its XML id attribute "p" is not
a part of that import.
╵
# In the document "CarbohydrateIdeas.cellml". ╵
# All id attributes should be unique within this document. ╵
model: name = "Carbs" id = none specified ╵
├─ component: name = "Chocolate", id = "c" ╵
├─ component: name = "Porridge", id = "p" ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
└─ component: name = "Toast", id = "t"
└─ variable: name = "Peanutbutter", id = "p"
# Invalid: The variable Peanutbutter is not allowed to have an id of "p"
# as this conflicts with the component Porridge id "p" in the same document.
See CellML syntax
<!-- In the file BreakfastMenu.cellml: -->
<model name="BreakfastOfChampions" id="b">
<component name="Protein" id="p" />
<import href="CarbohydrateIdeas.cellml">
<!-- Valid: The id attribute value is set here to be "c"
rather than that of the import, "p" -->
<component name="Carbohydrates" id="c" component_ref="Porridge" />
</import>
<!-- Valid: The name attributes are repeated, but in different element types.
The id attributes are distinct. -->
<component name="FunStuff" id="f" />
<variable name="FunStuff" id="fs" units="sprinkles" />
</component>
</model>
<!-- In the file CarbohydrateIdeas.cellml: -->
<model name="Carbs">
<!-- The id attribute "c" here does not clash with the Carbohydrates
component above as they are unknown to each other,
and in different documents. -->
<component name="Chocolate" id="c" />
<!-- Valid: The id attribute "p" here does not clash with the Protein
component id above because even though they are in the same model,
they are in different documents. -->
<component name="Porridge" id="p" />
<component name="Toast" id="t">
<!-- Invalid: The id attribute "p" here does clash with the component
Porridge above because they are in the same document. -->
<variable name="Peanutbutter" id="p" units="smooth" />
</component>
</model>
Some points to note:
Here we have two separate documents which are partially combined to make one model.
There is no repetition of
id
attribute values within the BreakfastMenu.cellml document.There is repetition of the
name
attribute “FunStuff”, but the elements have different types (component
andvariable
), so this remains valid.There is repetition of the
id
attribute “p” in the CarbohydrateIdeas.cellml document, between thevariable
named “Peanutbutter” and thecomponent
named “Porridge”. This is not valid.
Data representation formats in CellML¶
The following data representation formats are defined for use in this specification:
A CellML identifier:
SHALL consist of a single Basic Latin alphabetical character, which MAY be followed by any combination of Basic Latin alphanumerical characters and/or Basic Latin underscores.
SHALL, when comparing two identifiers, be considered identical to another identifier if and only if both identifiers are identical sequences of characters.
See more
Names and identifiers need to be a single word, and without any special characters other than an underscore. For example, these are allowed:
myName
,
my_name
,
myName1
,
… but these are not permitted:
my Name
has a space,
myName!
contains a special character, and
1myName
starts with a numerical character.
Note that CellML identifiers are case-sensitive, and empty strings are not allowed.
An integer string:
SHALL be a base 10 representation of an integer.
SHALL, other than the sign indicator, consist of one or more digits.
See more
An integer string is simply a string containing only the numerical characters between 0 and 9.
If it’s a negative then it should begin with the minus sign, -
, if it’s positive it may begin with the plus sign, +
.
A basic real number string:
SHALL be a base 10 representation of a real number.
MAY contain a single decimal point separator, which SHALL be the Basic Latin full stop character U+002E.
SHALL, other than the sign indicator and the decimal point separator, consist of one or more digits.
See more
Note that the basic real number string is distinct from the real number string in that it does not include real numbers in scientific notation (also called scientific form, standard index form, or standard form).
For example:
"-123.4567"
is a valid basic real number string,
"-1.234567E03"
is not (but it is a valid real number string),
"+123.4567"
is not valid (must not contain the plus sign+
),
"1234567"
is valid (it’s ok to not use a decimal point.
),
"123,4567"
is not valid (the decimal signifier must be a full-stop symbol.
),
"123,456.7"
is not valid (you may not use a comma,
or a space :code:` ` as a thousands separator),
"12.34.56"
is not valid (maximum of one decimal point.
is permitted), and
"0x123abc"
is not valid (base 10 numbers only).
A real number string:
SHALL be a base 10 representation of a real number \(r=s \times 10^e\) where \(s\) is the significand, a real number, and \(e\) is the exponent, an integer.
The representation of the number SHALL be the representation of the significand, optionally followed by a representation of the exponent.
The significand SHALL be represented as a basic real number string.
An exponent SHALL be represented by an exponent separator character, followed by the integer string representation of the value of the exponent. The exponent separator character SHALL be either the Basic Latin “E” character U+0045 or the Basic Latin “e” character U+0065.
If the exponent representation is omitted, the exponent shall be zero.
See more
Note that the real number string is distinct from the basic real number string in that it includes numbers in scientific notation (also called scientific form, standard index form, or standard form).
Where it does not contain an exponent term, the number is interpreted as if it was a basic real number string: the exponent term is effectively zero.
For example:
"1.234E03"
is a valid real number string,
"+1.234E03"
is not valid (must not contain the plus sign+
in the significand),
"1.234E+03"
is valid (a plus sign+
sign is permitted in the exponent),
"1.234E+3.0"
is not valid (the exponent must be an integer),
"1.234e3"
is valid (either case of E or e is permitted),
"123,45E03"
is not valid (the decimal signifier must be a full-stop symbol.
),
"123.45"
is valid, and is treated as if it were a basic real number string: the exponent term is effectivly zero,
"123.45E"
is not valid (if the exponent is present it may not be blank),
"123,456.7e89"
is not valid (you may not use a thousands separator), and
"0x123abc"
is not valid (base 10 numbers only).
Element information items¶
The model
element¶
The top-level element information item in a CellML infoset MUST be an element in the CellML namespace with a local name equal to model
.
In this specification, the top-level element is referred to as the model
element.
Every
model
element MUST contain aname
attribute.The value of the
name
attribute MUST be a CellML identifier.
See more
The model
is the highest level in the CellML file, not including the opening xml
tags.
And, just like the Highlander, there can be only one.
These are valid CellML name attributes:
myValidName
is valid (both cases are permitted),
my_other_valid_name
is valid (underscores are permitted), and
this1too
is valid (numerals 0-9 are permitted).
These are not valid CellML name attributes:
my invalid name
is not valid (spaces are not permitted),
thisIsInvalidToo!
is not valid (special characters other than the underscore_
are not permitted),
1amNotValidEither
is not valid (must not begin with a number), and
" "
empty string is not valid (a name must be present).
A
model
element MAY contain one or more additional specific element children, each of which MUST be of one of the following types:A
component
element;A
connection
element;An
encapsulation
element;An
import
element; orA
units
element.
See more
<model name="myModel">
<component name="myFirstComponent"> ... </component>
<component name="aDuplicatedComponentName"> ... </component>
<!-- INVALID: This component is not valid because it has the same name as an existing one. -->
<component name="aDuplicatedComponentName"> ... </component>
<units name="myUnits"> ... </units>
<units name="myOtherUnits"> ... </units>
<units name="aDuplicatedUnitName"> ... </units>
<!-- INVALID This units item is not valid because it has the same name as an existing units item. -->
<units name="aDuplicatedUnitName"> ... </units>
<!-- A model can contain any number of import items. -->
<import />
<import />
<!-- A model can contain any number of connection items, as long as the things they connect are unique. -->
<connection />
<connection />
<encapsulation>...</encapsulation>
<!-- INVALID: A model must contain only ONE encapsulation item. -->
<encapsulation>...</encapsulation>
<!-- INVALID: The only child elements of the model are those stated. -->
<apples> ... </apples>
</model>
A
model
element MUST NOT contain more than oneencapsulation
elements.
See more
The encapsulation of a model defines the nested structure of its components.
This in turn affects which variables have access to which other variables, and allows the modular behaviour to happen at any level.
For this reason, there can be only one encapsulation
item in any model.
For more information about encapsulation, please refer to 2.13 The encapsulation element.
The import
element¶
An import
element information item (referred to in this specification as an import
element) is an element in the CellML namespace with a local name equal to import
, which appears as a child of a model
element.
Every
import
element MUST contain an attribute in the namespacehttp://www.w3.org/1999/xlink
, with a local name equal tohref
.The value of this attribute SHALL be a valid locator
href
, as defined in Section 5.4 of the XLink specification [6].The
href
attribute SHALL be treated according to the XLink specification [6], by applying the rules for simple-type elements.When describing an
import
element or one of its children, the phrase “imported CellML infoset” SHALL refer to the CellML infoset obtained by parsing the document referenced by thehref
attribute.
See more
At present the location specified by the href
attribute must be a locally available file (not online).
The path may either be absolute from the root directory, or relative to the importing model’s location.
For example, here’s a model based around casting for The Wizard of Oz.
In the main model (the one doing the importing), the component used to play Dorothy is defined by importing a component
named judy_garland
from the file called role_of_dorothy.cellml
and setting its reference in the main file to be the component named dorothy
.
Note the file structure: the path to the imported file is specified relative to the importing file, in this case role_of_dorothy.cellml
sits inside a folder called characters
.
oz_model.cellml
<model name="oz">
<import xlink:href="characters/role_of_dorothy.cellml">
<component name="dorothy" component_ref="judy_garland" />
</import>
...
</model>
characters/dorothy.cellml
<model name="candidates_for_dorothy">
<component name="judy_garland"> ... </component>
...
<import xlink:href="toto.cellml">
<component name="judy_garlands_dog" component_ref="a_terrier_called_terry"/>
</import>
</model>
characters/role_of_toto.cellml
<model name="candidates_for_toto">
<component name="a_terrier_called_terry"> ... </component>
<component name="scooby_doo"> ... </component>
</model>
The component representing Toto could be imported in one of two ways, both giving identical model representations.
Either directly from the role_of_toto.cellml
file, or indirectly via the role_of_dorothy.cellml
file:
<model name="oz">
<import xlink:href="characters/role_of_dorothy.cellml">
<component name="dorothy" component_ref="judy_garland" />
</import>
<!-- Either directly from the "role_of_toto.cellml" file ... -->
<import xlink:href="characters/role_of_toto.cellml">
<component name="toto" component_ref="a_terrier_called_terry" />
</import>
<!-- ... OR indirectly through the role_of_dorothy.cellml" file. -->
<import xlink:href="characters/role_of_dorothy.cellml">
<component name="toto" component_ref="judy_garlands_dog" />
</import>
</model>
Every
import
element MAY contain one or more specific element children, each of which MUST be of one of the following types:An
import component
element; orAn
import units
element.
See more
The only items which can be imported directly are component
and units
items.
The intention is that these are modular building blocks, able to be passed between models easily through this import functionality.
When you import a component
, all its variables
and encapsulated child component
items are imported too, along with any its governing math
block and any units
items it uses.
When you import a units
item, the child unit
items which it contain are imported as well.
Any CellML infoset imported, directly or indirectly, by the imported CellML infoset MUST NOT be semantically equivalent to the importing CellML infoset (see 1.2.3.3 regarding semantic equivalence).
See more
The intention behind this restriction is to prevent circular import definitions from occurring.
Models are able to import twins, that is, component
or units
items which are identical in content but under different names.
Models may not import themselves, because this would create an infinite loop of dependence.
For example, the first Olsen twins model below is permitted: the same component is imported twice under different names.
<model name="olsen_twins">
<import xlink:href="twin_sister.cellml">
<component name="mary_kate" component_ref="sister"/>
</import>
<import xlink:href="twin_sister.cellml">
<component name="ashley" component_ref="sister"/>
</import>
<model>
This recursive import is not permitted because a component cannot import itself:
<!-- In a file called "multiplicity.cellml": -->
<model name="multiplicity">
<import xlink:href="multiplicity.cellml">
<component name="doug" component_ref="doug"/>
</import>
<model>
The sames applies for “indirect” imports, where recursion is created over several files:
<!-- In a file called "multiplicity.cellml": -->
<model name="multiplicity">
<import xlink:href="clone.cellml">
<component name="doug" component_ref="clone"/>
</import>
<model>
<!-- In a file called "clone.cellml": -->
<model name="first_clone">
<import xlink:href="clone_of_clone.cellml">
<component name="clone" component_ref="another_clone"/>
</import>
</model>
<!-- In a file called "clone_of_clone.cellml": -->
<model name="repeating_cloning">
<import xlink:href="multiplicity.cellml">
<component name="another_clone" component_ref="doug"/>
</import>
</model>
The import units
element¶
An import units
element information item (referred to in this specification as an import units
element) is an element in the CellML namespace with a local name equal to units
, which appears as a child of an import
element.
Every
import units
element MUST contain aname
attribute.The value of the
name
attribute MUST be a CellML identifier.The value of the
name
attribute MUST NOT be identical to the value of thename
attribute of any otherunits
orimport units
element in the CellML infoset.The value of the
name
attribute MUST NOT be identical to the name of any of the units listed in Table 3.1: Built-in units (see 3.2 Units references).
Read more
Importing units means that you’re assured of consistency between your models, and allows for a more modular reuse of the components which use them. There are three ingredients required in importing any item:
A destination item in the importing model (this is the
units
item calledsmallPotOfPaint
in the example below).A file to import from, specified using the
xlink:href
attribute of the parentimport
block. This is discussed in more detail in 2.2 The import element. In the example below this is thepaint_pot_sizes.cellml
file.The specific item name to retrieve from the imported file. In the example below this is the
twoLitrePot
value passed to theunits_ref
attribute.
Thus we can read the import statement below as: “retrieve the units
named twoLitrePot
from the file paint_pot_sizes.cellml
, and store it here in this model under the name potOfPaint
”.
<import xlink:href="paint_pot_sizes.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<units units_ref="twoLitrePot" name="potOfPaint"/>
</import>
Note that if you’ve already defined the namespace inside the <model>
tags then you would not need to repeat it here.
Imported items have the same restrictions as concrete items regarding the uniqueness of their names.
In the example below, the name potOfPaint
is used for the locally defined units in line 2, but the same name is used as the name for the imported units in line 6.
This is not permitted as it violates the unique name requirement.
<model name="paintingTheHouse">
<units name="potOfPaint">
<unit units="metre" exponent="3" multiplier="0.002">
</units>
<!-- This destination name conflicts with the locally defined name above -->
<import xlink:href="paint_pot_sizes.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<units units_ref="twoLitrePot" name="potOfPaint"/>
</import>
<component name="paintCalculator">
...
</component>
</model>
Every
import units
element MUST contain aunits_ref
attribute.The value of the
units_ref
attribute MUST be a CellML identifier.The value of the
units_ref
attribute MUST be identical to the value of thename
attribute on aunits
orimport units
element in the imported CellML infoset.
The import component
element¶
An import component
element information item (referred to in this specification as an import component
element) is an element in the CellML namespace with a local name equal to component
, which appears as a child of an import
element.
Every
import component
element MUST contain aname
attribute.The value of the
name
attribute MUST be a CellML identifier.The value of the
name
attribute MUST NOT be identical to the value of thename
attribute of any othercomponent
orimport component
element in the CellML infoset.
Every
import component
element MUST contain acomponent_ref
attribute.The value of the
component_ref
attribute MUST be a CellML identifier.The value of the
component_ref
attribute MUST be identical to the value of thename
attribute on acomponent
orimport component
element in the imported CellML infoset.
See more
The ablility to import and reuse component
items is one of the most powerful features in CellML, as it allows modellers to easily plug-n-play different variations and model parts.
There are three ingredients required in importing any item:
A destination in the importing model (this is the
component
item calledpi_calculator
in the example below),A file to import from, specified using the
xlink:href
attribute of the parentimport
block. This is discussed in more detail in 2.2 The import element. In the example below this is thepi_approximators.cellml
file.The specific item name to retrieve from the imported file. In the example below this is the
circumference_over_diameter
value passed to thecomponent_ref
attribute.
Thus we can read the import statement below as: “retrieve the component
named circumference_over_diameter
from the file pi_approximators.cellml
, and store it here in this model under the name pi_calculator
”.
<import xlink:href="pi_approximators.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<component component_ref="circumference_over_diameter" name="pi_calculator"/>
</import>
Things to watch out for:
The namespace. Note that if you’ve already defined the
xmlns:xlink
namespace inside the<model>
tags then you would not need to repeat it here.The name attribute. Imported items have the same restrictions as locally defined items regarding the uniqueness of their names and their format. In the example below, the name
pi_calculator
is used for the locally defined component in line 2, but the same name is used as the name for the imported component in line 6. This is not permitted as it violates the uniqueness requirement for names specified above. The second imported component uses an invalid name attribute (see 1.3 Data representation formats in CellML) so is not permitted either.
<model name="circle">
<component name="pi_calculator">
...
</component>
<!-- This destination name conflicts with the locally defined name above: -->
<import xlink:href="series_approx_of_pi.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<component component_ref="GregoryLeibnizApproximator" name="pi_calculator"/>
</import>
<!-- This destination name is not valid CellML as it contains whitespace and special characters: -->
<import xlink:href="series_approx_of_pi.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<component component_ref="GregoryLeibnizApproximator" name="pi calculator!"/>
</import>
</model>
The component_ref attribute. This must be a valid CellML identifier (see 1.3 Data representation formats in CellML). It also has to actually exist as a
component
in the givenhref
location! Neither of the imports below are permitted:
<model name="circle">
<!-- This component_ref name does not exist at in the file specified: -->
<import xlink:href="series_approx_of_pi.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<component component_ref="I_dont_exist" name="pi_calculator"/>
</import>
<!-- This component_ref name is not a valid CellML identifier: -->
<import xlink:href="series_approx_of_pi.cellml" xmlns:xlink="http://www.w3.org/1999/xlink">
<component component_ref="I have spaces so am not a valid ID" name="pi_calculator"/>
</import>
</model>
The units
element¶
A units
element information item (referred to in this specification as a units
element) is an element in the CellML namespace with a local name equal to units
, which appears as a child of a model
element.
Every
units
element MUST contain aname
attribute.The value of the
name
attribute MUST be a CellML identifier.The value of the
name
attribute MUST NOT be identical to the value of thename
attribute of any otherunits
element orimport units
element in the CellML infoset.
The value of the
name
attribute MUST NOT be identical to the name of any of the units listed in Table 3.1: Built-in units (see 3.2 Units references).
A
units
element MAY contain one or moreunit
element children.
See more
The best way to understand how units
work is to read the informative sections within the 2.6 The unit element in the next section, which defines their child unit
items.
The following examples show examples of what is not permitted when defining units
items.
<!-- The units name attribute is not a valid CellML identifier. -->
<units name="I'm not valid!"> ... </units>
<!-- Duplicted local units names are not allowed. -->
<units name="duplicatedName"> ... </units>
<units name="duplicatedName"> ... </units>
<!-- Duplicated name of an imported units item is not allowed. -->
<import xlink:href="handyUnitsForImport.cellml">
<units units_ref="myCustomUnits" name="duplicatedName">
</import>
<!-- Duplicating the name of built-in units is not allowed. -->
<units name="metre"> ... </units>
The unit
element¶
A unit
element information item (referred to in this specification as a unit
element) is an element in the CellML namespace with a local name equal to unit
, which appears as a child of a units
element.
Every
unit
element MUST contain aunits
attribute.The value of the
units
attribute MUST be a valid units reference, as defined in 3.2 Units references.
The
units
element inclusion digraph SHALL contain an arc fromunits
element A tounits
element B if and only ifunits
element A contains aunit
element with aunits
attribute value that is identical to thename
attribute value ofunits
element B.
The
units
element inclusion digraph MUST NOT contain any cycles.
See more
A Units
item is simply a collection of Unit
items, each with a prefix
, multiplier
, and exponent
.
They can be nested and contain multiple generations of inheritance, which means that there’s always a possibility of circular definitions: these are not permitted.
For example, the first definition is valid:
<!-- Defining new base units called A: -->
<units name="A"/>
<!-- Defining new units called B, equivalent to 1000.A^2 -->
<units name="B">
<unit units="A" prefix="kilo" exponent="2"/>
</units>
<!-- Defining new units called C, equivalent to B^3/ms or (1000)^3.A^6/ms -->
<units name="C">
<unit units="B" exponent="3"/>
<unit units="second" prefix="milli" exponent="-1"/>
</units>
The second definition creates a circular dependency, and is not valid:
<!-- Defining units called A which depend on units B: -->
<units name="A">
<unit units="B" exponent="2"/>
</units>
<!-- Defining units called B which depend on units C: -->
<units name="B">
<unit units="C" prefix="kilo" exponent="-2"/>
</units>
<!-- Defining units called C which depend on A: -->
<units name="C">
<unit units="A" prefix="mega"/>
<unit units="second" prefix="milli" exponent="-1"/>
</units>
A
unit
element MAY contain any of the following attributes:The
prefix
attribute.If present, the value of the attribute MUST meet the constraints specified in 3.3 Interpretation of units elements.
The
multiplier
attribute.If present, the value of the attribute MUST be a real number string.
The
exponent
attribute.If present, the value of the attribute MUST be a real number string.
Note
For the purpose of this specification, the units
element inclusion digraph SHALL be defined as a conceptual digraph which SHALL contain one node for every units
element in the CellML model.
See more
There are two items related to units in CellML, and their naming can be confusing!
The plural form, units
, represents the units to be used in the model by being assigned to variable
and cn
elements.
A units
item is a collection of smaller unit
items which transform the base dimensionality into the form required by the final units by way of prefixes, multipliers, and exponents.
In the example, we’ll need to use two of the built-in base units, metre
and second
, and manipulate them to form cm3/s.
This is done by including child unit
items.
First, we need to change the base units of metre
into cm3/s:
<units name="cm3_per_second">
<unit units="metre" prefix="centi" exponent="3"> <!-- The default multiplier is 1. -->
...
</units>
Next, we include the time dependency, changing the built-in units second
into s-1.
Note that sibling unit
items within a parent units
item are simply multplied together to form the final representation:
<units name="cm3_per_second">
<unit units="metre" prefix="centi" exponent="3"> <!-- Note default multiplier of 1. -->
<unit units="second" exponent="-1"> <!-- Note default prefix of 0, default multiplier of 1. -->
</units>
This is exactly equivalent to the alterantives below:
<units name="cm3_per_second">
<unit units="metre" prefix="-2" exponent="3"> <!-- A prefix can be specified as a power of 10. -->
<unit units="second" exponent="-1">
</units>
<!-- or ... -->
<units name="cm3_per_second">
<unit units="metre" exponent="3" multiplier="0.01"> <!-- A multiplier is specified instead of a prefix. -->
<unit units="second" exponent="-1">
</units>
<!-- or ... -->
<units name="cm3_per_second">
<unit units="metre" prefix="centi"> <!-- Note default exponent of 1 ... -->
<unit units="metre" prefix="-1"> <!-- ... is repeated ... -->
<unit units="metre" multiplier="0.01"> <!-- ... to give the equivalent power of 3. -->
<unit units="second" exponent="-1">
</units>
For more information on units
items please refer to 2.5 The units element.
The component
element¶
A component
element information item (referred to in this specification as a component
element) is an element in the CellML namespace with a local name equal to component
, which appears as a child of a model
element.
See more
Components are a convenient way to modularise a model, and allow parts to be removed, replaced, and reused easily. They define the scope of their contents, meaning that the items within a component need only be uniquely named in that local scope. Commonly needed variables (like time, for example) can be given the same name in multiple components without triggering an error.
Components are the largest building blocks of the model, and have three important parts to them.
The first is their naming and contents, similar to all the other CellML items, and described below.
The second relates to their structure in relation to other component
items: this structure is called their encapsulation and is described in 2.13 The encapsulation element.
The third relates to the import component
item, as described in 2.4 The import component element.
Every
component
element MUST contain aname
attribute.The value of the
name
attribute MUST be a CellML identifier.The value of the
name
attribute MUST NOT be identical to the value of thename
attribute on any othercomponent
element orimport component
element in the CellML infoset.
See more
A component
item, as with every other part of CellML, must use a name unique to its scope, and obey the format definitions outlined in 1.3 Data representation formats in CellML.
For example:
<!-- This is valid: -->
<component name="myValidName"> ... </component>
<!-- Not valid: the units name attribute is not a valid CellML identifier. -->
<component name="I'm not valid!"> ... </component>
<!-- Not valid: duplicted component names are not allowed. -->
<component name="duplicatedName"> ... </component>
<component name="duplicatedName"> ... </component>
<!-- Not valid: duplicating the name of an imported component item is not allowed. -->
<import xlink:href="handyComponentsForImport.cellml">
<component component_ref="myComponentRef" name="duplicatedName">
</import>
A
component
element MAY contain one or more specific element children, each of which MUST be of one of the following types:A
math
element;A
reset
element; orA
variable
element.
See more
The mathematics of a component
Perhaps the most important part of a component
item is the mathematics it contains.
This is stored inside a collection of <math>
blocks as described in 2.12 The math element.
The math
then defines the operation of the local variable
items and how they relate to each other mathematically.
For example, a component to calculate Einstein’s \(E=mc^2\) could be represented by:
<component name="mass_into_energy">
<math>
<apply><eq/>
<ci>E</ci>
<apply><times/>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<cn cellml:units="dimensionless">2</cn>
</apply>
</apply>
</apply>
</math>
...
</component>
Please refer to 2.12 The math element for information on the math
items and MathML format.
The variables of a component
The MathML block above refers to three variables named E
, m
and c
.
These variable names must be the same as the name
attributes of the child variable
items in this component.
<component name="mass_into_energy">
...
<variable name="E" units="joule" />
<variable name="m" units="kilogram" />
<variable name="c" units="metres_per_second" />
</component>
Please refer to 2.8 The variable element for information on variable
items.
The reset items of a component
Please refer to 2.9 The reset element for more information on reset
items.
The variable
element¶
A variable
element information item (referred to in this specification as a variable
element) is an element in the CellML namespace with a local name equal to variable
, which appears as a child of a component
element.
Every
variable
element MUST have exactly one of each of the following attributes:The
name
attribute.The value of the
name
attribute MUST be a CellML identifier.The value of the
name
attribute MUST NOT be identical to the value of thename
attribute on any siblingvariable
element.
The
units
attribute.The value of the
units
attribute MUST be a valid units reference, as defined in 3.2 Units references.
Every
variable
element MAY contain one or more of the following attributes:The
interface
attribute.If the attribute is present, it MUST have value of
public
,private
,public_and_private
, ornone
.
The
initial_value
attribute.If the attribute is present, it MUST meet the requirements described by 3.6 Interpretation of initial_value attributes.
See more
In addition to the standard name
attribute, each variable
must also define a units
attribute too.
Reusing Einstein’s example from 2.7 The component element section we can give the three variables their fuller definitions:
<component name="mass_into_energy">
<math>
...
</math>
<variable name="E" units="joule"/>
<variable name="m" units="kilogram"/>
<variable name="c" units="metre_per_second"/>
</component>
Extra attributes that can be used as needed include the initial_value
, which will either set a constant value for a variable, or set its initial conditions if it’s being solved for.
More information about initialisation can be found in 3.6 Interpretation of initial_value attributes.
Finally, where one variable
(A) has been mapped to another (B) in a different component (BB), both A and B must specify interface
attributes.
These prescribe the relative positions in the encapsulation that the components AA and BB must have in order for their respective variables A and B to access one another.
This is outlined in more detail in 2.13 The encapsulation element.
The reset
element¶
A reset
element information item (referred to in this specification as a reset
element) is an element in the CellML namespace with a local name equal to reset
, which appears as a child of a component
element.
See more
Understanding reset elements
Resets are a new addition to CellML in version 2.0, and their intention is to allow the user to specify how and when discontinuities can exist in variable values throughout the solution. A reset lets you set a variable to a totally different value: restart a timer, flip a switch, take a step, start again. In order to work, a reset needs to know some information:
Which variable’s value do you want to change? This is called the “reset variable” and is specified by the
variable
attribute in thereset
block.What new value should be given to the reset variable? This is called the “reset value” and is specified by evaluating the MathML content which is inside the
reset_value
element child of thisreset
element.Which variable will tell us when to trigger the change? This is called the “test variable” and is referenced by the
test_variable
attribute in thereset
block. The test variable can be the same as the reset variable.What value of the test variable should be used to trigger the change? This is called the “test value” and is specified by evaluating the MathML content inside the
test_value
element child of thisreset
element.What happens if more than one reset points to the same reset variable? This will be sorted out by the unique
order
attribute on eachreset
element which changes this reset variable. The order will determine which of the active competing resets is applied.
Some of the syntax is explained below in the “see more” sections, and a final example is given at the end.
For a much more thorough discussion and examples of resets in different scenarios, please see the
{number} {name}
section.
Every
reset
element MUST have exactly one of each of the following attributes:The
variable
attribute.The value of the
variable
attribute MUST be a valid variable reference, as defined in 3.5 Variable references.
The
test_variable
attribute.The value of the
test_variable
attribute MUST be a valid variable reference, as defined in 3.5 Variable references.
The
order
attribute.The value of the
order
attribute MUST be an integer string.The value of the
order
attribute MUST be unique for allreset
elements withvariable
attributes that reference variables in the same equivalent variable set (see 3.10 Interpretation of map_variables elements).
See more
Consider the following example which represents the mythological story of Sisyphus, king of Ephrya. He was condemned to roll a huge boulder up a mountain each day, but, as it reached the top, the boulder would roll to the bottom so he had to begin again.
model: Tartarus
└─ component: Sisyphus
├─ math: ode(position, time) = 1 [metres_per_second]
├─ variable: time [second]
└─ variable: position, initially 0 [metre]
└─ reset:
├─ when: time is midnight
└─ then: position is bottom of hill
In this example it’s clear that for the reset to operate, it must know what is happening and when; in other words, that the variable
attribute as well as the test_variable
attribute must be specified.
This is shown in the CellML syntax block below.
Show CellML syntax
<!-- This is valid: both the reset variable "position" and the
test_variable "time" are in the same component as the reset
which uses them. -->
<model name="Tartarus">
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="metre" initial_value="0" />
<reset variable="position" test_variable="time" order="1">
<!-- The reset_value and test_value children of a reset are
discussed in the next sections. -->
...
</reset>
<!-- ODE for position based on time. -->
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="metres_per_second">1</cn>
</apply>
</math>
</component>
<!-- Custom units required by ODE above: -->
<units name="metres_per_second" >
<unit units="metre" />
<unit units="second" exponent="-1" />
</units>
</model>
Examples of invalid configurations include when either the variable
or test_variable
attributes are unspecified, or when they do not refer to variables local to the reset’s component.
Show CellML syntax
<model name="Tartarus">
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="dimensionless" initial_value="0" />
<!-- This is not valid: The test variable has not been specified. -->
<reset variable="position" order="1">
...
</reset>
<!-- This is not valid: The reset variable has not been specified. -->
<reset test_variable="time" order="1">
...
</reset>
...
</component>
</model>
<model name="Tartarus">
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="metre" />
<!-- This is not valid: The test variable "eternity_time" does not exist
in the reset's component. -->
<reset variable="position" test_variable="eternity_time" order="1">
...
</reset>
...
</component>
</model>
<model name="Tartarus">
<!-- This is not valid: The reset variable "position" is in component Sisyphus ... -->
<component name="Sisyphus">
<variable name="position" units="metre" initial_value="0" />
</component>
<!-- ... but the reset which changes it is in component "RulerOfTartarus". -->
<component name="RulerOfTartarus">
<variable name="time" units="second" />
<reset variable="position" test_variable="time" order="1">
...
</reset>
</component>
</model>
The
order
attribute.
The value of the
order
attribute MUST be an integer string.The value of the
order
attribute MUST be unique for allreset
elements withvariable
attributes that reference variables in the same equivalent variable set (see 3.10 Interpretation of map_variables elements).
See more
The order
attribute of a reset
element must be specified, and is used when there is more than one reset with the ability to change a variable.
We’ll continue the example above which represents the mythological story of Sisyphus rolling a boulder up a mountain, but tweak it a little.
The ruler of Tartarus has decided that Sisyphus should have a day off on Tuesdays, so once a week the boulder doesn’t roll down the mountain until the following midnight.
Adding a second reset
to the model gives us the arrangement shown below.
model: Tartarus
└─ component: Sisyphus
├─ math: ode(position, time) = 1
├─ variable: time
└─ variable: position, initially 0
├─ reset: A
│ ├─ when: time is midnight
│ ├─ then: position is bottom of hill
│ └─ order: 2
│
└─ reset: B
├─ when: time is Tuesday midnight
├─ then: position is unchanged at top of hill
└─ order: 1
As it stands, at midnight on a Tuesday both of the resets above are active: the first, reset A, because midnight on any day meets the midnight criterion; the second because midnight on Tuesday also meets the criterion for B.
To decide which of the two consequences to enact - to roll the stone or not - we need to consider the order
attribute, the interpretation of which is discussed in detail in {number} {name}
.
The valid CellML syntax for this situation is shown below, with some examples of invalid syntax too.
Show CellML syntax
<!-- This is valid: the order attribute of both resets is present,
unique, and an integer. -->
<model name="Tartarus">
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="dimensionless" />
<!-- The first reset represents all midnight times. -->
<reset variable="position" test_variable="time" order="2">
...
</reset>
<!-- The second reset represents midnight on Tuesdays only. -->
<reset variable="position" test_variable="time" order="1">
...
</reset>
</component>
</model>
<!-- These are not valid: -->
<model name="Tartarus">
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="dimensionless" initial_value="0" />
<!-- Invalid: missing order attribute. -->
<reset variable="position" test_variable="time" >
...
</reset>
<!-- Invalid: order must be an integer. -->
<reset variable="position" test_variable="time" order="first" >
...
</reset>
<reset variable="position" test_variable="time" order="1.0" >
...
</reset>
</component>
</model>
Finally we’ll look at the condition for uniqueness of a variable’s resets’ orders. Note that this is applied within the component itself across all the resets which could apply to a given variable, as well as across the set of equivalent variables too. Let’s create a second component to represent the whim of Zeus, ruler of the gods, who can intervene at any time to send the stone rolling down the mountain.
model: Tartarus
├─ component: Zeus
│ └─ variable: sisyphus_position <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
│ └─ reset: C ╷
│ ├─ when: Sisyphus reaches some position ╷
│ ├─ then: sisyphus_position is bottom of hill ╷
│ └─ order: -1 ╷
│ equivalent
└─ component: Sisyphus variables
├─ math: ode(position, time) = 1 ╵
├─ variable: time ╵
└─ variable: position <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
├─ reset: A
│ ├─ when: time is midnight
│ ├─ then: position is bottom of hill
│ └─ order: 2
│
└─ reset: B
├─ when: time is Tuesday midnight
├─ then: position is unchanged at top of hill
└─ order: 1
Show CellML syntax
<model name="Tartarus">
<!-- Including a new component with a connected variable, sisyphus_position: -->
<component name="Zeus" >
<variable name="sisyphus_position" units="metre" initial_value="0" interface="public"/>
<!-- Creating a reset that will send the boulder to the bottom of the mountain
when it reaches a certain point: -->
<reset variable="sisyphus_position" test_variable="sisyphus_position" order="-1">
...
</reset>
</component>
<component name="Sisyphus">
<variable name="time" units="second" />
<variable name="position" units="dimensionless" interface="public" />
<!-- The first reset represents all midnight times. -->
<reset variable="position" test_variable="time" order="2">
...
</reset>
<!-- The second reset represents midnight on Tuesdays only. -->
<reset variable="position" test_variable="time" order="1">
...
</reset>
...
</component>
<!-- Connecting the variable "position" in component "Sisyphus" with the variable
"sisyphus_position" in component "Zeus": -->
<connection component_1="Zeus" component_2="Sisyphus" >
<map_variables variable_1="sisyphus_position" variable_2="position" />
</connection>
</model>
This arrangement is valid, because none of the order
attributes on resets within the same equivalent variable set have duplicated values: reset A has order 2, reset B has order 1, and reset C has order -1.
Note also that order values may be negative, as shown here.
Gotcha: an “equivalent variable set” without any equivalent variables?
The equivalent variable set rule here refers to any reset which references the same variable. This is possible in two ways - either by directly referencing it (as in resets A and B above) or through the equivalence network (as in reset C). Thus, even in situations where there are no equivalent variables defined in the model (which is the case before Zeus stepped in) there is still the need for order uniqueness between resets of the same variable (as in between A and B).
A
reset
element MUST contain exactly two element children, which MUST be one of each of the following types:A
reset_value
element; and
A
test_value
element.
The test_value
element¶
A test_value
element information item (referred to in this specification as a test_value
element) is an element in the CellML namespace with a local name equal to test_value
, which appears as a child of a reset
element.
A
test_value
element MUST contain exactly onemath
element child.
See more
The test_value
(like the reset_value
) block takes a slightly different kind of MathML statement to those in the component
elements.
Because the the left hand side of the equation has already been effectively defined by specifying the test_variable
, the math
child of a test_value
needs only to specify the right hand side.
This means that the normal opening block of <apply><eq/><ci>left_hand_side_variable</ci> ... </apply>
is omitted:
<reset variable="position" test_variable="height_above_the_floor_in_metres" order="1"/>
<test_value>
<math>
<cn cellml:units="metre">1.0</cn>
</math>
</test_value>
<reset_value>
<math>
<apply><plus/>
<apply><abs/>
<apply><minus/>
<cn cellml:units="metre">1</cn>
<ci>position</ci>
</apply>
</apply>
<cn cellml:units="metre">1.0</cn>
</apply>
</math>
</reset_value>
</reset>
In the above example, the position of a ball above a 1 metre high table is maintained, as every time it appears to drop below the table-level datum of position=1.0
it is reset to a “bounced” value greater than 1.0 instead.
For the reset
to be useful, the equations it contains need to make sense.
Be sure to check that the units that you’re using within the test_value
block match those of the test_variable
against which it will be compared.
In this example the reset_value
(the new position of the ball over the table) must be in metres to match the variable
's units, as with the test_value
which must match the units of the test_variable
.
A mismatch of units here doesn’t mean you have an invalid CellML 2.0 model, but it does mean that it may not behave in the way you are expecting!
The reset_value
element¶
A reset_value
element information item (referred to in this specification as a reset_value
element) is an element in the CellML namespace with a local name equal to reset_value
, which appears as a child of a reset
element.
A
reset_value
element MUST contain exactly onemath
element child.
See more
The test_value
(like the reset_value
) block takes a slightly different kind of MathML statement to those in the component
elements.
Because the the left hand side of the equation has already been effectively defined by specifying the test_variable
, the math
child of a test_value
needs only to specify the right hand side.
This means that the normal opening block of <apply><eq/><ci>left_hand_side_variable</ci> ... </apply>
is omitted:
<reset variable="position" test_variable="height_above_the_floor_in_metres" order="1"/>
<test_value>
<math>
<cn cellml:units="metre">1.0</cn>
</math>
</test_value>
<reset_value>
<math>
<apply><plus/>
<apply><abs/>
<apply><minus/>
<cn cellml:units="metre">1</cn>
<ci>position</ci>
</apply>
</apply>
<cn cellml:units="metre">1.0</cn>
</apply>
</math>
</reset_value>
</reset>
In the above example, the position of a ball above a 1 metre high table is maintained, as every time it appears to drop below the table-level datum of position=1.0
it is reset to a “bounced” value greater than 1.0 instead.
For the reset
to be useful, the equations it contains need to make sense.
Be sure to check that the units that you’re using within the test_value
block match those of the test_variable
against which it will be compared.
In this example the reset_value
(the new position of the ball over the table) must be in metres to match the variable
's units, as with the test_value
which must match the units of the test_variable
.
A mismatch of units here doesn’t mean you have an invalid CellML 2.0 model, but it does mean that it may not behave in the way you are expecting!
The math
element¶
A math
element information item (referred to in this specification as a math
element) is an element in the MathML namespace, which appears as a child of a component
element, a test_value
element, or a reset_value
element.
A
math
element MUST be the top-level element of a Content MathML tree, as described in MathML 2.0 [7].
See more
Because MathML is an entire language in its own right, we just don’t have the ability to go through all its general aspects here. Some great general resources are available on the MathML 2.0 site, and we’ll discuss below the more CellML specific restrictions in the other “See more” sections.
Please note that MathML 2 content markup is the only syntax used in CellML, even though more recent versions (MathML 3 and MathML 4) are available.
Each element child of a
math
element MUST have an element-type name that is listed in Table 2.1: Supported MathML elements.
See more
Probably the biggest aspect of CellML’s restrictions of MathML is that it is confined to using only MathML2 content markup. No form of presentation markup is permitted, and only the version MathML2 is allowed (i.e.: not MathML 3 or greater).
The basics
The types of block can be divided into two broad categories: operation items and information items. For example, the calculation of Einstein’s \(E=mc^2\) could be represented by:
<math>
<apply><eq/>
<ci>E</ci>
<apply><times/>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<cn cellml:units="dimensionless">2</cn>
</apply>
</apply>
</apply>
</math>
The code below is similar, but with the mistakes as listed:
<math>
<apply><eq/>
<!-- The line below is not valid because <ci> elements cannot specify units;
their units are taken from the units of the variable
(even though in this case, E really does have units Joules). -->
<ci cellml:units="joule">E</ci>
<!-- The <apply> operation below is missing an operation argument (it should be <times/>) -->
<apply>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<!-- The contents of a <cn> block below must be a real number, not a variable. -->
<!-- It must also define units in the cellml namespace, i.e.: units:cellml="myUnits". -->
<cn>variable_with_value_of_two</cn>
</apply>
</apply>
</apply>
</math>
The contents of a MathML
ci
element MUST be a valid variable reference, as defined in 3.5 Variable references.
See more
Consider the same \(E=mc^2\) formula as earlier, but now the value of mass m
is calculated in another component:
<component name="mass_into_energy">
<!-- The local variables for energy E and speed of light c are listed here ... -->
<variable name="E" units="joule"/>
<variable name="c" units="metres_per_second"/>
<!-- ... but the variable for mass calculated in another component. -->
<math>
<apply><eq/>
<ci>E</ci>
<apply><times/>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<cn cellml:units="dimensionless">2</cn>
</apply>
</apply>
</apply>
</math>
</component>
<component name="calculate_mass">
<variable name="m" units="kilograms" initial_value="54" />
</component>
This situation is not valid, as the math
block in component mass_into_energy
doesn’t have access to the variable m
in the component calculate_mass
.
To get around this, you would need to create a new local variable within the mass_into_energy
component, and use a connection
element to link it to the mass variable m
in the other component.
The valid form of the model is shown below. You can read more about connections
in 2.15 The connection element, and the interface_type
attribute in 2.8 The variable element.
<component name="mass_into_energy">
<variable name="E" units="joule"/>
<variable name="c" units="metres_per_second"/>
<!-- A new local variable named m is created here with a public interface type. -->
<variable name="m" units="kilograms" interface_type="public"/>
<math>
<apply><eq/>
<ci>E</ci>
<apply><times/>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<cn cellml:units="dimensionless">2</cn>
</apply>
</apply>
</apply>
</math>
</component>
<component name="calculate_mass">
<variable name="mass" units="kilograms" initial_value="54" />
</component>
<!-- A connection element is created which links components "calculate_mass" and "mass_into_energy". -->
<connection component_1="mass_into_energy" component_2="calculate_mass">
<!-- A map_variable pair is created which links the "m" variables in each of the connected components. -->
<map_variables variable_1="m" variable_2="m" />
</connection>
A MathML
cn
element MUST have an attribute in the CellML namespace, with a local name equal tounits
.The value of the
units
attribute MUST be a valid units reference, as defined in 3.2 Units references.
A MathML
cn
element MUST be base 10.A
cn
element MUST be one of the following types: real or e-notation.
See more
Constants using the <cn>
tags
When specifying a constant with <cn>
, its real number value is given between the tags, and its units are specified as an attribute.
<!-- These are valid: Note the cellml namespace for the units. -->
<cn cellml:units="customUnitsDefinedInTheModel">35.3</cn> <!-- Units which exist in the model are permitted. -->
<cn cellml:units="litre">10</cn> <!-- Built-in units (with UK spelling) are permitted. -->
<cn cellml:units="dimensionless">3.14159e+03</cn> <!-- Scientific or e-notation is permitted. -->
Please note that the units name specified must refer to a units
element that exists in the model
element, or be one from the Built-in Units table.
<!-- These are not valid: -->
<cn cellml:units="unitsThatDontExist">35.3</cn> <!-- The units reference must exist in the model. -->
<cn>42</cn> <!-- Units must be specified. -->
<cn some_other_namespace:units="some_units">502.642</cn> <!-- Units must be in the cellml namespace. -->
<cn cellml:units="meter">26.6</cn> <!-- Built-in unit names must be in UK spelling, i.e.: metre, litre. -->
<cn cellml:units="dimensionless">3,000</cn> <!-- Must be a valid real number string, the comma separator is not permitted. -->
<cn cellml:units="dimensionless">+4.0</cn> <!-- The plus sign indicator is not permitted except in e-notation exponents. -->
<cn cellml:units="dimensionless">0x235abc</cn> <!-- The value must be in base 10. -->
<cn cellml:units="dimensionless">i_am_a_variable</cn> <!-- Only real number values are permitted in <cn> blocks. -->
Dimensional consistency (or, how to write nonsense maths)
For a model to have a valid CellML syntax, it needs to follow the MathML rules outlined above. But it’s still possible to create nonsense (should you so desire … ), and one great way to create nonsense is to have MathML statements which have inconsistent units. Consider again Einstein’s equation \(E=mc^2\). Now imagine that encode it into CellML like this:
<variable name="E" units="joule"/>
<variable name="c" units="lumen"/>
<variable name="m" units="weber"/>
<math>
<apply><eq/>
<!-- Nonsense alert! Left hand side units of joules ... -->
<ci>E</ci>
<!-- ... but right hand side units of (weber).(lumen)^(volt)! -->
<apply><times/>
<ci>m</ci>
<apply><power/>
<ci>c</ci>
<!-- Nonesense alert! Units in an exponent? -->
<cn cellml:units="volt">2</cn>
</apply>
</apply>
</apply>
</math>
Believe it or not, this is valid! (Perhaps it’s better to say it’s not invalid).
It’s clearly nonsense, but it doesn’t actually violate any syntax rules.
The only instance where you will create an invalid model by assigning units
to variables
is when you need to form a map_variables
pair with a variable
in another component
.
In this case, each variable
must have an equivalent unit reduction or it won’t be valid CellML.
Element Category |
Element List |
Simple Operands |
|
Basic Structural |
|
Relational and Logical Operators |
eq , neq , gt , lt , geq ,leq , and , or , xor , not |
Arithmetic Operators |
plus , minus , times , divide ,power , root , abs ,exp , ln , log ,floor , ceiling ,min , max , rem |
Calculus Elements |
|
Qualifier Elements |
|
Trigonometric Operators |
sin , cos , tan , sec ,
csc , cot ,sinh , cosh , tanh , sech ,
csch , coth ,arcsin , arccos , arctan ,arcsec , arccsc , arccot ,arcsinh , arccosh , arctanh ,arcsech , arccsch , arccoth |
Mathematical and Logical Constants |
pi , exponentiale ,
notanumber ,infinity , true , false |
The encapsulation
element¶
An encapsulation
element information item (referred to in this specification as an encapsulation
element) is an element in the CellML namespace with a local name equal to encapsulation
, which appears as a child of a model
element.
An
encapsulation
element MAY contain one or morecomponent_ref
element children.
See more
Encapsulation is the way that CellML manages the hierarchy of components and keeps their modularity.
This is why there can be only one encapsulation
element within a model
: you can think of it as a table of contents for components in the whole model.
Encapsulations don’t have to include all of the model’s components; only the ones which need to sit within another component.
Components which are not listed within the encapsulation are top-level children of the model
.
<!-- Valid encapsulation structure. This will give the arrangement of:
- grandad
- father
- child
- aunt
- orphan
Because the component named "orphan" is not included in the encapsulation
it will stay at the top level of the model. -->
<model name="I_am_a_valid_model">
<component name="grandad"/>
<component name="aunt"/>
<component name="father"/>
<component name="child"/>
<component name="orphan">
<encapsulation>
<component_ref component="grandad">
<component_ref component="aunt"/>
<component_ref component="father">
<component_ref component="child"/>
</component_ref>
</component_ref>
</encapsulation>
</model>
<!-- Invalid: More than one encapsulation is not permitted. -->
<model name="too_many_encapsulations">
<component name="parent1"/>
<component name="child1"/>
<component name="parent2"/>
<component name="child2"/>
<encapsulation>
<component_ref component="parent1">
<component_ref component="child2"/>
</component_ref>
</encapsulation>
<encapsulation>
<component_ref component="parent2">
<component_ref component="child2"/>
</component_ref>
</encapsulation>
</model>
<!-- Invalid: A component cannot appear more than once in an encapsulation. -->
<model name="duplicated_component_ref">
<component name="parent"/>
<component name="child"/>
<encapsulation>
<component_ref component="parent">
<component_ref component="child">
<component_ref component="parent"/>
</component_ref>
</component_ref>
</encapsulation>
</model>
<!-- Valid, but redundant: An encapsulation can be empty, but this is the default
condition so its inclusion alters nothing. -->
<model name="empty_encapsulation">
<component name="parent"/>
<component name="child"/>
<encapsulation>
</encapsulation>
</model>
<!-- Valid, but redundant: An encapsulation must have a minimum of two levels of children
to affect the model's structure. This still represents the default condition. -->
<model name="duplicated_component_ref">
<component name="parent"/>
<component name="child"/>
<encapsulation>
<component_ref component="parent">
<!-- There has to be a child here or the parent is not a parent. -->
</component_ref>
</encapsulation>
</model>
The component_ref
element¶
A component_ref
element information item (referred to in this specification as a component_ref
element) is an element in the CellML namespace with a local name equal to component_ref
, which appears as a descendant of an encapsulation
element.
Every
component_ref
element MUST contain acomponent
attribute.The value of the
component
attribute MUST be a valid component reference, as defined in 3.4 Component references.The value of the
component
attribute MUST NOT be identical to the value of thecomponent
attribute on any othercomponent_ref
element in the CellML infoset.
Every
component_ref
element MAY in turn contain one or morecomponent_ref
element children.
See more
Please see the notes about the component_ref
usage under the “See more” link in 2.13 The encapsulation element.
The connection
element¶
A connection
element information item (referred to in this specification as a connection
element) is an element in the CellML namespace with a local name equal to connection
, which appears as a child of a model
element.
Each
connection
element MUST contain acomponent_1
attribute.The value of the
component_1
attribute MUST be a valid component reference, as defined in 3.4 Component references.
Each
connection
element MUST contain acomponent_2
attribute.The value of the
component_2
attribute MUST be a valid component reference, as defined in 3.4 Component references.
See more
Creating connection
items allows variable
values to be passed between eligible components
.
There are both syntactic (i.e.: format) and semantic (i.e.: meaning) rules about how these must be specified, including what “eligible” means.
Syntax will be discussed below and in the other “See more” blocks on this page.
For more on the semantic rules, please see 3.10 Interpretation of map_variables elements.
Both points above are really saying the same thing.
The way in which you specify the component_1
and component_2
items must follow the general CellML 2.0 format for a valid identifier, and must point to a component
which exists under that name (note that this could be either an intantiated component
, or an import component
item).
<!-- This is a valid CellML 2.0 connection: -->
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="romeo" variable_2="juliet">
</connection>
</model>
<!-- This is not valid: -->
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<!-- The component_2 attribute does not exist as a component or import component name.-->
<connection component_1="house_of_montague" component_2="CapuletWhanau">
<!-- The variable_1 name is not a valid CellML identifier. -->
<map_variables variable_1="Romeo, Romeo ..." variable_2="juliet">
</connection>
</model>
The value of the
component_1
attribute MUST NOT be identical to the value of thecomponent_2
attribute.
See more
All this means is that equivalent variables
(i.e.: those specified by connection
and map_variables
items) must be in different components
.
Since the only reason you’d need to use these connections is in order to access a variable
in another component
, this restriction does kinda make sense!
<model>
<component name="happily_ever_after">
<variable name="juliet" interface_type="public">
<variable name="romeo" interface_type="public">
</component>
<!-- This is not valid because component_1 and component_2 are the same. -->
<connection component_1="happily_ever_after" component_2="happily_ever_after">
<map_variables variable_1="romeo" variable_2="juliet">
</connection>
</model>
A CellML infoset MUST NOT contain more than one
connection
element with a given pair of components referenced by thecomponent_1
andcomponent_2
attribute values, in any order.
See more
You may only have one connection
any two components
, regardless of which is specified as component_1
and which is specified as component_2
.
If you have found duplicate connection
elements, simply merge their contents - a connection
can contain any number of map_variables
children.
Make sure that the order in which you specify the component
attributes matches the order in which you specify their child variable
items too: ie, all variable_1
items must be within the component_1
component and vice versa.
<!-- This is not valid CellML: -->
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
<variable name="rosaline" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="romeo" variable_2="juliet">
</connection>
<!-- This connection duplicates the one above, even though
component_1 and component_2 are swapped. -->
<connection component_1="capulet" component_2="montague">
<map_variables variable_1="rosaline" variable_2="romeo">
</connection>
</model>
<!-- This is now valid: The contents were merged to create a valid model. -->
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
<variable name="rosaline" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<!-- The contents have been merged. Note that the order of variables
must match the order of the parent component, i.e.: all variable_1s
must be within component_1 etc. -->
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="romeo" variable_2="juliet">
<map_variables variable_1="romeo" variable_2="rosaline">
</connection>
</model>
A
connection
element MAY contain one or moremap_variables
element children.
See more
The point of creating a connection
item is in order to connect variables
between eligible components
.
You are allowed to have an empty connection
, but it is meaningless.
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<!-- Valid but redundant: an empty connection is meaningless. -->
<connection component_1="montague" component_2="capulet">
</connection>
</model>
The map_variables
element¶
A map_variables
element information item (referred to in this specification as a map_variables
element) is an element in the CellML namespace with a local name equal to map_variables
, which appears as a child of a connection
element.
Each
map_variables
element MUST contain avariable_1
attribute.The value of the
variable_1
attribute MUST be a valid variable reference, as defined in 3.5 Variable references.
Each
map_variables
element MUST contain avariable_2
attribute.The value of the
variable_2
attribute MUST be a valid variable reference, as defined in 3.5 Variable references.
See more
The points above are both saying the same thing for their variable_1
and variable_2
attributes respectively:
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<!-- Valid: -->
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="romeo" variable_2="juliet">
</connection>
<!-- Invalid: the variable_1 value is not a valid CellML identifier (special characters and spaces). -->
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="Romeo, Romeo ..." variable_2="juliet">
</connection>
<!-- Invalid: the variable_2 value does not exist in component_2. -->
<connection component_1="montague" component_2="capulet">
<map_variables variable_1="romeo" variable_2="juliet_is_the_sun">
</connection>
</model>
A
connection
element MUST NOT contain more than onemap_variables
element with a givenvariable_1
attribute value andvariable_2
attribute value pair.
See more
Just as you can have only one connection
between any two components
, within that connection
you can have only one map_variables
item between any two variables
:
<model>
<component name="house_of_capulet">
<variable name="juliet" interface_type="public">
</component>
<component name="house_of_montague">
<variable name="romeo" interface_type="public">
</component>
<connection component_1="montague" component_2="capulet">
<!-- Invalid: Duplicate map_variables are not allowed. -->
<map_variables variable_1="romeo" variable_2="juliet">
<map_variables variable_1="romeo" variable_2="juliet">
</connection>
</model>
Interpretation¶
Interpretation of import
elements¶
Each
import units
orimport component
element present in a CellML infoset (the importing infoset) SHALL define a new and distinct instance of the CellML infoset (the imported infoset) that is specified by the parentimport
element’shref
attribute.A units reference occurring within an imported element, SHALL be resolved with respect to the imported infoset.
When determining the equivalent variable set of a variable in an imported component:
Connections defined in the importing infoset SHALL be handled as described in 3.10 Interpretation of map_variables elements.
Connections defined in the imported infoset SHALL be handled as follows:
Connections to components in the encapsulated set of the imported component SHALL be maintained, and this rule SHALL be applied recursively; and
Connections to components in the sibling set, or to the encapsulation parent of the imported component SHALL NOT be maintained.
See more
Please see the informative sections on 3.2 Units references and 3.4 Component references pages for examples specific to importing units
and component
elements.
Units references¶
A “units reference” is an attribute value that specifies the physical units a variable or number is in.
A units reference SHALL be a CellML identifier.
The units identified by a units reference SHALL be determined as follows:
If the units reference is identical to a value in the “Name” column of Table 3.1: Built-in units, then it SHALL refer to the built-in units from the same row of the table.
If the units reference is identical to the value of the
name
attribute of aunits
element in the same infoset, then it SHALL refer to the units specified by that element.If the units reference is identical to the value of the
name
attribute of animport units
element in the same infoset, then it SHALL refer to units from the infoset defined by theimport units
element (see 3.1 Interpretation of import elements).The units specified SHALL then be determined by treating the value of the
units_ref
attribute on theimport units
element as a units reference within the imported infoset.If necessary, this rule SHALL be applied recursively.
If no units can be identified using the rules above, the attribute value SHALL NOT be a valid units reference.
See more
Understanding units references
Units references are different from other reference types in that their value refers either to other units which you’ve imported or created in your model, or to one of the list of built-in units.
The trickier part is understanding them during an import process, where the scope or domain in which named units exist becomes important, as alluded to in points 3.2.1 and 3.2.2.2.
Consider the example below.
The first model BlueberryPieRecipe
simply combines two pre-made component ingredients; one for the crust and one for the filling.
model: BlueberryPieRecipe
├─ component: crust <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
└─ component: filling <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐ ╷
╷ ╷
imported components
╵ ╵
# In filling_recipes.cellml: ╵ ╵
model: PieFillingRecipes ╵ ╵
├─ component: BlueberryCinnamonFilling ╶┘ ╵
└─ component: AppleAndPearFilling ╵
╵
# In crust_recipes.cellml: ╵
model: PieCrustRecipes ╵
├─ component: HazelnutLavenderCrust ╴╴╴╴╴╴┘
└─ component: CheeseAndAlmondCrust
See CellML syntax
<!-- Inside the file "how_to_make_blueberry_pie.cellml": -->
<model name="BlueberryPieRecipe">
<import xlink:href="relative/path/to/my/crust_recipes.cellml">
<component name="crust" component_ref="HazelnutLavenderCrust" />
</import>
<import xlink:href="relative/path/to/my/filling_recipe.cellml">
<component name="filling" component_ref="BlueberryCinnamonFilling" />
</import>
</model>
The components are imported from separate files, each of which defines and uses its own local definitions of the custom measurement units spoon
, dash
, and smidgen
.
model: BlueberryPieRecipe
├─ component: crust <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
└─ component: filling <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐ ╷
╷ ╷
imported components and
the units they need
╵ ╵
# In filling_recipes.cellml: ╵ ╵
model: PieFillingRecipes ╵ ╵
├─ component: BlueberryCinnamonFilling ╴╴╴┬┬┘ ╵
│ ├─ variable: blueberries (gram) ╷╷ ╵
│ ├─ variable: sugar (dimensionless) units are implicitly
│ ├─ variable: cornflour (gram) imported by the component
│ ├─ variable: cinnamon ╵╵ ╵
┌╴╴╴╴╴╴╴╴╴> └─ units: smidgen ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╵ ╵
╷ | └─ variable: water ╵ ╵
╷┌╴╴╴╴╴╴╴╴╴> └─ units: spoonful ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵
╷╷ | ╵
╷╷ ├─ component: AppleAndPearFilling ╵
╷╷ | ╵
local custom units ╵
╵╵ | ╵
╵└╴╴├─ units: spoonful ╵
└╴╴╴└─ units: smidgen ╵
╵
# In crust_recipes.cellml: ╵
model: PieCrustRecipes ╵
├─ component: HazelnutLavenderCrust ╴╴╴╴╴╴╴┬┬┬┘
│ ├─ variable: ground_hazelnut (gram) ╷╷╷
│ ├─ variable: egg (dimensionless) ╷╷╷
│ ├─ variable: flour (gram) units are implicitly
│ ├─ variable: sugar (gram) imported by the component
│ ├─ variable: water ╵╵╵
┌╴╴╴╴╴╴╴╴╴╴> └─ units: spoonful ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╵╵
╷ │ ├─ variable: salt ╵╵
╷┌╴╴╴╴╴╴╴╴╴> └─ units: dash ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╵
╷╷ │ └─ variable: lavender_flowers ╵
╷╷┌╴╴╴╴╴╴╴╴> └─ units: smidgen ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
╷╷╷ │
local custom units
╵╵╵ │
╵╵╵ ├─ component: CheeseAndAlmondCrust
╵╵╵ │
╵╵└╴├─ units: smidgen
╵└╴╴├─ units: dash
└╴╴╴├─ units: spoonful
└─ units: dollop
See CellML syntax
<!-- Inside the file "crust_recipes.cellml": -->
<model name="PieCrustRecipes">
<component name="HazelnutLavenderCrust">
<!-- These units are built-in so do not change. -->
<variables name="ground_hazelnut" units="gram" />
<variables name="egg" units="dimensionless" />
<variables name="flour" units="gram" />
<variables name="sugar" units="gram" />
<!-- These units are defined for this, their local scope, below. -->
<variables name="water" units="spoonful" />
<variables name="salt" units="dash" />
<variables name="lavender_flowers" units="smidgen" />
...
</component>
<component name="CheeseAndAlmondCrust">
...
</component>
<!-- Local units definitions for spoonful, dash, and smidgen. -->
<units name="spoonful">
<unit units="litre" prefix="milli" multiplier="15" />
</units>
<units name="dash">
<unit units="gram" multiplier="5" />
</units>
<units name="smidgen">
<unit units="gram" multiplier="1" />
</units>
<units name="dollop">
<unit units="litre" prefix="milli" multiplier="20" />
</units>
</model>
<!-- Inside the file "filling_recipes.cellml": -->
<model name="PieFillingRecipes">
<component name="BlueberryCinnamonFilling">
<!-- These units are built-in, so do not change. -->
<variables name="blueberries" units="gram" />
<variables name="sugar" units="dimensionless" />
<variables name="cornflour" units="gram" />
<!-- These units are defined for use in this, their local scope, below. -->
<variables name="cinnamon" units="smidgen" />
<variables name="water" units="spoonful" />
<math>
...
</math>
</component>
<component name="AppleAndPearFilling">
...
</component>
<!-- Local units definitions for spoonful and smidgen. -->
<units name="spoonful">
<unit units="litre" prefix="milli" multiplier="5" />
</units>
<units name="smidgen">
<unit units="gram" multiplier="20" />
</units>
</model>
This is where the idea of scope becomes important.
As it stands, there is no conflict between the two different definitions of spoonful
and smidgen
, because each of the components refers to its own definition of these units.
The components do not “know” that there is any other definition out there, because they cannot “see” up into the importing model.
Now let’s consider that the cook wants to alter the recipe a little after these two main ingredients have been imported, by adding a spoonful of brandy to some custard. The top-level model becomes:
model: BlueberryPieRecipe
├─ component: BrandyCustard
│ ├─ variable: custard (litre)
│ └─ variable: brandy
│ └─ units: spoonful # These units are not defined in a scope
│ which this component can access:
│ the model is invalid.
├─ component: crust <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
└─ component: filling <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐ ╷
╷ ╷
imported components
╵ ╵
# In filling_recipes.cellml: ╵ ╵
model: PieFillingRecipes ╵ ╵
├─ component: BlueberryCinnamonFilling ╶┘ ╵
└─ component: AppleAndPearFilling ╵
╵
# In crust_recipes.cellml: ╵
model: PieCrustRecipes ╵
├─ component: HazelnutLavenderCrust ╴╴╴╴╴╴┘
└─ component: CheeseAndAlmondCrust
See CellML syntax
<!-- Inside the file "how_to_make_blueberry_pie.cellml": -->
<model name="BlueberryPieRecipe">
<import xlink:href="relative/path/to/my/crust_recipes.cellml">
<component name="premade_crust" component_ref="HazelnutLavenderCrust" />
</import>
<import xlink:href="relative/path/to/my/filling_recipe.cellml">
<component name="yummy_filling" component_ref="BlueberryCinnamonFilling" />
</import>
<!-- Defining a new component, brandy custard -->
<component name="BrandyCustard">
<variable name="custard" units="litre" />
<variable name="brandy" units="spoonful" />
...
</component>
</model>
At this stage the model is invalid because the units spoonful
in the top-level model are not defined. Just as the imported models cannot “see” up into the importing model, neither can the importing model “see” down into the imported models beyond those items which it has explicitly imported.
In order to reuse the spoonful
units from either of the imported models, they must be explicitly imported. The top-level model becomes:
model: BlueberryPieRecipe
├─ component: BrandyCustard
│ ├─ variable: custard (litre)
│ └─ variable: brandy
┌╴╴╴╴╴╴╴╴> └─ units: spoonful
╷ ├─ component: crust <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
╷ ├─ component: filling <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐ ╷
╷ │ ╷ ╷
└╴╴╴└─ units: spoonful <╴╴╴╴╴╴╴┐ imported components and
╷ the units they need
explicitly imported units ╵ ╵
are available to all components ╵ ╵
╵ ╵ ╵
# In filling_recipes.cellml: ╵ ╵ ╵
model: FillingRecipeCollection ╵ ╵ ╵
├─ units: spoonful ╴╴╴╴╴╴╴╴╴╴┘ ╵ ╵
├─ component: BlueberryCinnamonFilling ╶┘ ╵
└─ component: AppleAndPearFilling ╵
╵
# In crust_recipes.cellml: ╵
model: PieCrustRecipes ╵
├─ component: HazelnutLavenderCrust ╴╴╴╴╴╴┘
└─ component: CheeseAndAlmondCrust
See CellML syntax
<!-- Inside the file "how_to_make_blueberry_pie.cellml": -->
<model name="BlueberryPieRecipe">
<import xlink:href="relative/path/to/my/crust_recipes.cellml">
<component name="premade_crust" component_ref="HazelnutLavenderCrust" />
</import>
<import xlink:href="relative/path/to/my/filling_recipe.cellml">
<component name="yummy_filling" component_ref="BlueberryCinnamonFilling" />
</import>
<!-- Defining a new component, brandy custard -->
<component name="BrandyCustard">
<variable name="custard" units="litre" />
<variable name="brandy" units="spoonful" />
...
</component>
<!-- Explicitly importing the "spoonful" units from the "filling_recipes.cellml" file: -->
<import xlink:href="relative/path/to/my/filling_recipe.cellml">
<!-- The units are also called "spoonful" in this top-level scope. -->
<units name="spoonful" component_ref="spoonful" />
</import>
</model>
At this stage we have three sets of units all named “spoonful”.
Since each is only accessible to its local components there is no conflict of definition or interpretation.
Now that the units required in the new BrandyCustard
component are defined within the same scope, the model becomes valid, and our dessert needs are satisfied once more.
Name
|
Unit reduction tuple
multiplier⋅(base, exponent)
|
|
- |
|
( |
|
- |
|
( |
|
- |
|
( |
|
0.001⋅( |
|
( |
|
( |
|
( |
|
( |
|
( |
|
- |
|
- |
|
0.001⋅( |
|
( |
|
( |
|
- |
|
- |
|
( |
|
( |
|
( |
|
( |
|
- |
|
( |
|
( |
|
( |
|
( |
|
( |
|
( |
|
( |
Interpretation of units
elements¶
The
units
element SHALL be interpreted as the product of itsunit
element children, according to the following rules:The prefix term is a conceptual property of
unit
elements.If the
unit
element does not have aprefix
attribute, then the prefix term SHALL have value 0.If the
prefix
attribute has a value which is an integer string, then the value of the prefix term SHALL be the numerical value of that string.If the
prefix
attribute has a value which is not an integer string, then the attribute MUST have a value taken from the “Name” column of Table 3.2: Prefix values, and the prefix term SHALL have the value taken from the “Value” column of the same row.
The exponent term is a conceptual property of
unit
elements.If a
unit
element has noexponent
attribute, then the exponent term SHALL have value 1.0.If a
unit
element has anexponent
attribute, then the exponent term MUST be a real number string, and the value of the exponent term SHALL be the numerical value of that string.
The multiplier term is a conceptual property of
unit
elements.If a
unit
element has nomultiplier
attribute, then the multiplier term SHALL have value 1.0.If a
unit
element has amultiplier
attribute, then the multiplier MUST be a real number string, and the value of the multiplier term SHALL be the numerical value of that string.
The relationship between the product, \(P\), of numerical values given in each and every child
unit
element’sunits
attribute, to a numerical value, \(x\), with units given by the encompassingunits
element, SHALL be\[x[u_x] = {\dfrac {1} {m_1 \dotsm m_n(10^{p_1})^{e_1} \dotsm (10^{p_1})^{e_n}}} { \left[ \dfrac {u_x}{u^{e_1} \dotsm u^{e_n}} \right ] }P \left[ u^{e_1} \dotsm u^{e_n} \right]\]where \(u_x\) denotes the units of the
units
element; \(p_i\), \(e_i\), \(m_i\) and \(u_i\) refer to the prefix, exponent and multiplier terms and units of the \(i^{th}\)unit
child element, respectively. Square brackets encompass the units of numerical values.
See more
Prefixes
The prefix
term is different from the other attributes of a unit
element in that it can accept both a string (the name of the prefix from the Prefix table) or an integer (the base 10 log equivalent to the prefix).
It’s also different because it will become invalid if a non-integer real number is used.
For example, these are equivalent:
<!-- This is valid ... -->
<unit units="myOtherUnits" prefix="3">
<!-- ... is the same as ... -->
<unit units="myOtherUnits" prefix="kilo">
<!-- ... and the same as this. -->
<unit units="myOtherUnits" multiplier="1000.0">
<!-- BUT this is not valid, the prefix MUST be an integer or prefix name only! -->
<unit units="myOtherUnits" prefix="3.">
Note: These examples are only equivalent because the exponent
in each case is 1.
Multipliers and exponents
As you might expect, both the exponent
and multiplier
attributes must be valid real numbers, which could include an integers.
(This is in contrast to the prefix
which must be an integer or a named prefix.)
All three attributes can be combined in different ways to give the same effective outcome.
The examples below all define a units
item equivalent to a 330 mL bottle of beer.
<!-- The prefix can be an integer or a named prefix: -->
<units name="bottle_of_beer">
<unit units="metre" prefix="-2" exponent="3.0" multiplier="330" />
</units>
<units name="bottle_of_beer">
<unit units="metre" prefix="centi" exponent="3.0" multiplier="330" />
</units>
<!-- Note that exponents are added to the combination of prefix and units terms
only, not to the muptiplier:
i.e.: this is (0.33)*((deci)(metre))^3
-->
<units name="bottle_of_beer">
<unit units="metre" prefix="deci" exponent="3.0" multiplier="0.33"/>
</units>
<!-- A missing prefix has no effect: -->
<units name="bottle_of_beer">
<unit units="metre" exponent="3.0" multiplier="3.3e-4"/>
</units>
<!-- Repeated unit items can be included:
- the three centimetres together give 1 mL, and
- the dimensionless multiplier makes them 330 mL.
-->
<units name="bottle_of_beer">
<unit units="metre" prefix="centi"/>
<unit units="metre" prefix="centi"/>
<unit units="metre" prefix="centi"/>
<unit units="dimensionless" multiplier="330.0"/>
</units>
Note: All spellings of built-in units and prefixes must be UK (not US) English, i.e.: metre
(not meter), litre
(not liter), and deca
(not deka).
Combinations
Once you’ve read above how single unit
items can be combined to form a units
item, you’ll also need to define how units
items can be used to form generations of units.
Using the same example of the 330mL beer bottle as before, here are alternative, but equivalent, definitions.
<units name="bottle_of_beer">
<unit units="millilitre" multiplier="330">
</units>
<!-- Of course, we need to define the "millilitre" unit before the above is valid: -->
<units name="millilitre">
<unit units="litre" prefix="milli" /> <!-- Note UK spelling! -->
</units>
<!-- The above is equivalent to: -->
<units name="millilitre">
<unit units="metre" prefix="centi" exponent="3.0" /> <!-- Note UK spelling! -->
</units>
But we can also use child units
in conjunction with exponents
too.
In this situation you’ll need to understand the equation above. Let’s start by defining a centimeter:
<units name="centimeter">
<unit units="metre" multiplier="0.01"/>
</units>
<!-- ... or ... -->
<units name="centimeter">
<unit units="metre" prefix="centi"/>
</units>
<!-- ... or ... -->
<units name="centimeter">
<unit units="metre" prefix="-2"/>
</units>
Now cube it to get the units of millilitres:
<units name="millilitre">
<unit units="centimetre" exponent="3.0"/>
</units>
This is equivalent to creating the units of (10-6)(metre
)3, because the effect of the exponent
is applied to the combination of units
and prefix
, but not to the multiplier
. For example:
<!-- So this ... -->
<units name="millilitre">
<unit units="metre" exponent="3.0" multiplier="1e-6" />
</units>
<!-- ... is equivalent to this: -->
<units name="millilitre">
<units units="metre" exponent="3.0" prefix="-2" />
</units>
It’s good to get your head around the difference between how the multiplier
and prefix
terms work, or your scaling might not be quite what you expect (and your beer disappointing).
For the purposes of this specification, the “irreducible units” of a model SHALL consist of:
The units defined in a model that are not defined in terms of other units (i.e. the set of
units
elements in the CellML model which have nounit
child elements).The built-in irreducible units (those built-in units with “-” in the “Unit reduction tuple” column of Table 3.1: Built-in units) referenced by variables or other units in the model.
See more
The terms “irreducible units” and “unit reduction” really need to be understood together, but before either make sense we need to explain the concept of “base units”. In the physical world there are seven base units defined in the SI (Système International d’Unités) system. These are:
Symbol |
Name |
Base quantity |
s |
second |
time |
m |
metre |
length |
kg |
kilogram |
mass |
A |
ampere |
electric current |
K |
kelvin |
thermodynamic temperature |
mol |
mole |
amount of substance |
cd |
candela |
luminous intensity |
Some of the units listed in the Built-in Units table are these base units, but others are combinations of them included for convenience. Only those rows in the table which have no entries in the “Unit reduction” column are “irreducible” or base units.
In the CellML 2.0 world you are able to also define your own base units.
These are units
items which you create which do not reference any child unit
items (thus rendering them “irreducible”).
For example:
<!-- Define a new base unit called "egg".
It's a base unit because it has no child unit items. -->
<units name="egg">
</units>
<!-- Define other units which use this new base unit. -->
<units name="dozen_eggs">
<unit units="egg" multiplier="12" />
</units>
<!-- Combine the new base unit with existing built-in units: eggs/m^2. -->
<units name="eggs_per_square_metre">
<unit units="egg" />
<unit units="metre" exponent="-2" />
</units>
The terms “irreducible units” and “unit reduction” are used when discussing situations where the units of two variables must be equivalent. It makes no sense to equate a variable with units of seconds to another with units of kilograms, for example. The same is true for more complicated versions of units, as outlined in the next section.
The “unit reduction” is a conceptual property of
units
elements. It consists of a set of tuples where each tuple is composed of a “unit name” and a real-valued “exponent”. The set of tuples SHALL be determined as follows:If the
units
element has nounit
child elements, then the set of tuples SHALL have a single member, which SHALL consist of the name of theunits
element and the exponent 1.0.If the
units
element has one or moreunit
child elements, then the set of tuples SHALL consist of the entire collection of tuples given by allunit
child elements.Tuples for each
unit
child element SHALL be determined as follows:If the units reference of the
unit
child element is to a single unit which is an irreducible unit, then the set of tuples SHALL have a single member, which SHALL consist of the name of the irreducible unit being referenced and the exponent 1.0.
If the units reference of the
unit
child element is to built-in units other than an irreducible unit, then the tuples SHALL be derived directly from Table 3.1: Built-in units. Specifically, the set of tuples SHALL consist of the tuples given in the “Unit reduction tuple” column of the row for which the value in the “Name” column is identical to the name of the units reference.
If the units reference of the
unit
child element is to a unit which is neither built-in, nor an irreducible unit, then the set of tuples SHALL be defined recursively as the set of tuples for theunits
element so referenced.The exponents of each tuple in the set for the current
unit
element, as derived by following rules 3.3.3.2.1, 3.3.3.2.2 or 3.3.3.2.3 above, SHALL be multiplied by the exponent term of the current, referencing,unit
element.
Tuples which have the unit name of “dimensionless” SHALL be removed from the set of tuples. Note that this can result in the set of tuples being empty.
If the set of tuples contains tuples which have the same unit name, then those tuples SHALL be combined into a single tuple with that unit name and an exponent being the sum of those tuples’ exponents. If the resulting tuple’s exponent is zero, then the tuple SHALL be removed from the set of tuples. Note that this can result in the set of tuples being empty.
See more
Unit reduction
As discussed in the previous “See more” block, “irreducible” or “base” units are those fundamental quantities which cannot be expressed in any other way.
This includes user-defined base units too.
The “unit reduction” of any units
item is simply a recipe for how any units item is constructed from these “base unit” ingredients.
For example, the units “metres per second” could be written:
m/s,
m⋅s-1,
product[ (metre)^1 , (second)^-1 ]
, or
product[ power(metre, 1) , power(second, -2) ]
.
This final list of tuples - representing the base unit and its exponent - is referred to as the unit reduction tuples for the units
element.
Some other examples are given below.
Related to :hardcodedref:`3.3.3.2.1`:
<!-- Unit reduction: [ (metre, 1), (second, -1) ] -->
<units name="metres_per_second">
<unit units="metre">
<unit units="second" exponent="-1>
</units>
Related to :hardcodedref:`3.3.3.2.2`: joule
s are equivalent to kg⋅m2⋅s:sup:−2, and the extra “per second” takes the effective exponent for second
to -3.
<!-- Unit reduction: [ (kilogram, 1), (metre, 2), (second, -3) ] -->
<units name="joules_per_second">
<unit units="joule" />
<unit units="second" exponent="-1" />
</units>
Related to :hardcodedref:`3.3.3.2.3 and 4`: The concentration of apples per litre of cider is expressed using the custom base units apple
, the custom derived units bushell_of_apples
and the built-in convenience units of litre
, the last being equivalent to 0.001m3.
Note that:
scaling does not affect the unit reduction tuples,
the custom derived units
bushell_of_apples
do not appear because it can be further reduced toapple
, andthe final exponent of the
metre
base unit comes from applying 3.3.3.2.4 and multiplying the exponent of the litre reduction tuple (metre, 3) with the exponent given in thecider_concentration
tuple (litre, -1) to give a (metre, -3) in the final unit reduction tuple set.
<!-- Unit reduction: [ (apple, 1), (metre, -3) ] -->
<units name="apple" />
<units name="bushell_of_apples">
<unit units="apple" multiplier="1000" />
</units>
<units name="cider_concentration">
<unit units="bushell_of_apples" multiplier="0.5" />
<unit units="litre" exponent="-1" />
</units>
Dimensionless base units
You may have noticed in the Built-in Units that there is an entry labelled dimensionless
.
This is provided for convenience, and doesn’t take part in determining the unit reduction for any units
items.
Together with the next point, this means that the all unit reduction tuples represent the minimum possible description of a units
item.
For example, this units
item has the unit reduction of (metre, 1)
:
<!-- The "dimensionless" base units do not appear in the unit reduction. -->
<units name="metres_by_dimensionless">
<unit units="metre">
<unit units="dimensionless" exponent="3">
</units>
Combining unit reductions
As outlined above, the built-in base units dimensionless
do not contribute to the unit reduction tuple set.
This holds for built-in units which are effectively dimensionless (like radian
and steradian
) but also for situations in which base units’ exponents could be simplified or cancelled.
For example, all of the units
items below have identical unit reduction tuples of (metre, 1), (second, -1)
:
<units name="metres_per_second">
<unit units="metre">
<unit units="second" exponent="-1">
</units>
Here the metre
exponents of 3 and -4 reduce to 1:
<units name="metres_per_second_too">
<unit units="metre" exponent="4">
<unit units="second" exponent="-1">
<unit units="metre" exponent="-3">
</units>
Here the steradian
inclusion has no effect on the final unit reduction as its own units cancel out:
<units name="metres_per_second_too">
<unit units="metre" exponent="1">
<unit units="second" exponent="-1">
<unit units="steradian" exponent="-3">
</units>
Finally a complicated one with the same outcome.
Note that even though there are some irreducible units used, they end up with an exponent of 0 in the tuple, and are therefore removed from the final unit reduction.
Note that a volt
V is equivalent to m2·kg·s-3·A-1.
<units name="orange" />
<units name="cubed_oranges">
<unit units="orange" exponent="3" />
</units>
<units name="mega_amps_per_gram">
<unit units="ampere" prefix="mega" exponent="1" />
<unit units="gram" exponent="-1" />
</units>
<units name="acceleration_units">
<unit units="metre" prefix="milli" />
<unit units="second" exponent="-2" />
</units>
<!-- Finally, combining these gives a units item with the same reduction as above -->
<units name="believe_it_or_not">
<unit units="orange" exponent="-3" />
<unit units="cubed_oranges" prefix="mega" />
<unit units="volt" prefix="zepto" />
<unit units="acceleration_units" exponent="-1" />
<unit units="mega_amps_per_gram" multiplier="3.14159" />
</units>
Name |
Value |
|
24 |
|
21 |
|
18 |
|
15 |
|
12 |
|
9 |
|
6 |
|
3 |
|
2 |
|
1 |
|
−1 |
|
−2 |
|
−3 |
|
−6 |
|
−9 |
|
−12 |
|
−15 |
|
−18 |
|
−21 |
|
−24 |
Component references¶
A “component reference” is an attribute value that specifies a CellML component.
A component reference SHALL be a CellML identifier.
The component identified by a component reference SHALL be determined as follows:
If the component reference is identical to the value of the
name
attribute of acomponent
element in the same infoset, then it SHALL refer to the component specified by that element.If the component reference is identical to the value of the
name
attribute of animport component
element in the same infoset, then it SHALL refer to a component from the infoset defined by theimport component
element (see 3.1 Interpretation of import elements).The component specified SHALL then be determined by treating the value of the
component_ref
attribute on theimport component
element as a component reference within the imported infoset.If necessary, this rule SHALL be applied recursively.
If no component can be identified using the rules above, then the attribute value SHALL NOT be a valid component reference.
See more
Understanding component references
As with references to units and variables, the term “component reference” refers to places where you need to refer to a component using its name.
This is done through the component_ref
attribute found in import component
and encapsulation
elements, as well as the component_1
and component_2
attributes of connection
elements.
The complicated part occurs during imports, and involves understanding the scope of a component’s reference. This is really just the appropriate name by which to call it depending on who is doing the calling.
Consider the following example.
Here, two families live next door to one another, and within each family use the terms “husband” and “wife” to refer to their own component members.
In the local “LeadbetterFamilyModel” and “GoodFamilyModel” model
contexts, “husband” and “wife” are the name
attributes of the local components
.
In the wider neighbourhood, however, each person must be referred to by their real-world name: “BarbaraGood”, “TomGood”, “JerryLeadbetter”, and “MargotLeadbetter”.
In the “SurbitonNeighbourhood” model
context, the real-world names of “BarbaraGood” etc. are treated as name
attributes of local component
elements (even though they’re imported), but now the “husband” and “wife” terms are component_ref
elements, as they are not the context providing the name.
model: SurbitonNeighbourhood
├─ component: TomGood <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
├─ component: BarbaraGood <╴╴╴╴╴╴╴╴╴┐ ╷
├─ component: MargotLeadbetter <╴╴╷ ╷ ╷
└─ component: JerryLeadbetter <╴┐ ╷ ╷ ╷
╷ ╷ ╷ ╷
imported components
╵ ╵ ╵ ╵
# In LeadbetterFamily.cellml: ╵ ╵ ╵ ╵
model: LeadbetterFamilyModel ╵ ╵ ╵ ╵
├─ component: husband ╴╴╴╴╴╴╴╴╴╴┘ ╵ ╵ ╵
└─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵ ╵
╵ ╵
# In GoodFamily.cellml: ╵ ╵
model: GoodFamilyModel ╵ ╵
├─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵
└─ component: husband ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="SurbitonNeighbourhood">
<!-- Importing two families into the neighbourhood. -->
<import xlink:href="GoodFamily.cellml">
<!-- Within the family, the members are called "wife" and "husband", but after
importing into the neighbourhood, these same components are now referred
to by the names "BarbaraGood" and "TomGood". -->
<component name="BarbaraGood" component_ref="wife" />
<component name="TomGood" component_ref="husband" />
</import>
<import xlink:href="LeadbetterFamily.cellml">
<!-- Even though the component_ref attributes here are the same as above
(i.e.: "wife" and "husband") they are interpreted within the context
of the imported model (i.e.: the "TheLeadbetterFamilyUnit" model imported
from the "LeadbetterFamily.cellml" file), and so refer to separate things.
-->
<component name="MargotLeadbetter" component_ref="wife" />
<component name="JerryLeadbetter" component_ref="husband" />
</import>
</model>
<!-- Inside the GoodFamily.cellml file: -->
<model name="TheGoodFamilyUnit">
<component name="husband" />
<component name="wife" />
</model>
<!-- Inside the LeadbetterFamily.cellml file: -->
<model name="TheLeadbetterFamilyUnit">
<component name="husband" />
<component name="wife" />
</model>
Now let’s make things more interesting by adding an encapsulation hierarchy:
model: SurbitonNeighbourhood
├─ component: WomenInTheNeighbourhood
│ ├─ component: BarbaraGood <╴╴╴╴╴╴╴╴╴╴╴┐
│ └─ component: MargotLeadbetter <╴╴╴╴┐ ╷
└─ component: MenInTheNeighbourhood ╷ ╷
├─ component: TomGood <╴╴╴╴╴╴╴╴╴╴╴┐ ╷ ╷
└─ component: JerryLeadbetter <╴┐ ╷ ╷ ╷
╷ ╷ ╷ ╷
imported components
╵ ╵ ╵ ╵
# In LeadbetterFamily.cellml: ╵ ╵ ╵ ╵
model: LeadbetterFamilyModel ╵ ╵ ╵ ╵
├─ component: husband ╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵ ╵ ╵
└─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┼╴┘ ╵
╵ ╵
# In GoodFamily.cellml: ╵ ╵
model: GoodFamilyModel ╵ ╵
├─ component: husband ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵
└─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="SurbitonNeighbourhood">
...
<component name="WomenInTheNeighbourhood" />
<component name="MenInTheNeighbourhood" />
<!-- Throughout the importing model (i.e.: this model), the imported
items are referred to by their local name attribute ("BarbaraGood" etc),
not the name they are called within their imported family units ("wife"). -->
<encapsulation>
<component_ref component="WomenInTheNeighbourhood">
<component_ref component="BarbaraGood" />
<component_ref component="MargotLeadbetter" />
</component_ref>
<component_ref component="MenInTheNeighbourhood">
<component_ref component="TomGood" />
<component_ref component="JerryLeadbetter" />
</component_ref>
</encapsulation>
</model>
This particular encapsulation structure means that the women (Barbara and Margot) are essentially unable to have any contact with the men (Tom and Jerry) even though their original components in the models from which they were imported were able to access one another.
Note also that these locality-based naming-calling rules will be applied through multiple generations of importing. Since The Good Life is a TV show, there are actors who play the roles of each of the characters. This could be reflected by using another generation of imports within the two family files like this:
model: SurbitonNeighbourhood
├─ component: WomenInTheNeighbourhood
│ ├─ component: BarbaraGood <╴╴╴╴╴╴╴╴╴╴╴╴╴┐
│ └─ component: MargotLeadbetter <╴╴╴╴╴╴┐ ╷
└─ component: MenInTheNeighbourhood ╷ ╷
├─ component: TomGood <╴╴╴╴╴╴╴╴╴╴╴╴╴┐ ╷ ╷
└─ component: JerryLeadbetter <╴╴╴┐ ╷ ╷ ╷
╷ ╷ ╷ ╷
imported components
╵ ╵ ╵ ╵
# In LeadbetterFamily.cellml: ╵ ╵ ╵ ╵
model: TheLeadbetterFamilyUnit ╵ ╵ ╵ ╵
┌╴╴╴╴╴╴╴╴> ├─ component: husband ╴╴╴╴╴╴╴┘ ╵ ╵ ╵
╷ ┌ ╴╴╴╴╴> └─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴┼╴┘ ╵
╷ ╷ ╵ ╵
╷ ╷ # In GoodFamily.cellml: ╵ ╵
╷ ╷ model: TheGoodFamilyUnit ╵ ╵
╷ ╷ ┌╴╴╴> ├─ component: husband ╴╴╴╴╴╴╴╴╴╴┘ ╵
╷ ╷ ╷ ┌╴> └─ component: wife ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
╷ ╷ ╷ ╷
imported components
╵ ╵ ╵ ╵
╵ ╵ ╵ ╵ # In CastOfCharacters.cellml:
╵ ╵ ╵ ╵ model:
╵ ╵ ╵ └╴╴╴├─ component: FelicityKendal
╵ ╵ └╴╴╴╴╴├─ component: RichardBriers
╵ └╴╴╴╴╴╴╴├─ component: PenelopeKeith
└╴╴╴╴╴╴╴╴╴└─ component: PaulEddington
See CellML syntax
<!-- Inside the GoodFamily.cellml file: -->
<model name="TheGoodFamilyUnit">
<import xlink:href="CastOfCharacters.cellml">
<component name="husband" component_ref="RichardBriers" />
<component name="wife" component_ref="FelicityKendal" />
</import>
</model>
<!-- Inside the LeadbetterFamily.cellml file: -->
<model name="TheLeadbetterFamilyUnit">
<import xlink:href="CastOfCharacters.cellml">
<component name="husband" component_ref="PaulEddington" />
<component name="wife" component_ref="PenelopeKeith" />
</import>
</model>
Note that in this situation, the original SurbitonNeighbourhood
model does not need to change at all.
Each of the component references remains correct, as each is isolated in its own scope.
Variable references¶
A “variable reference” is an attribute value that specifies a CellML variable.
A variable reference SHALL be a CellML identifier.
The variable identified by a variable reference SHALL be determined as follows:
If present in a descendant of a
component
element, then it SHALL refer to the variable of the same name within that component.If present in the
variable_1
attribute of amap_variables
element, then it SHALL refer to the variable of the same name in the component identified by thecomponent_1
attribute in the samemap_variables
element.If present in the
variable_2
attribute of amap_variables
element, then it SHALL refer to the variable of the same name in the component identified by thecomponent_2
attribute in the samemap_variables
element.
If no variable can be identified using the rules above, then the attribute value SHALL NOT be a valid variable reference.
See more
Understanding variable references
A variable
item only exists within its parent component
item, but can be connected to others via the map_variables
functionality.
There are two different ways that any variable
could be referenced.
The first and simplest is within its own local scope, the parent component
.
In that situation, the variable
element’s name
attribute is enough to uniquely locate it.
The second situation is when a variable
is referred to from a component
other than its parent, so a reference to the parent component
as well as the variable
’s name
is required.
This is found when creating connection
items using map_variables
.
The example below shows how the pairing of components and variables are required to form a valid connection.
<model name="FamousFreds">
<component name="Flintstone">
<variable name="Fred" units="dimensionless" />
<variable name="Wilma" units="dimensionless" />
</component>
<component name="Astair">
<variable name="Fred" units="dimensionless" />
</component>
<component name="CartoonCharacters">
<variable name="FredFlintstone" units="dimensionless" />
<variable name="DaffyDuck" units="dimensionless" />
</component>
<component name="Dancers">
<variable name="FredAstaire" units="dimensionless" />
<variable name="GingerRogers" units="dimensionless" />
</component>
<!-- Correct: connecting the variable "Fred" in component "Flintstone" into the
variable "FredFlintsone" in the "CartoonCharacters" component. -->
<connection component_1="Flintstone" component_2="CartoonCharacters" >
<map_variables variable_1="Fred" variable_2="FredFlintstone" />
</connection>
<!-- Incorrect: trying to connect variable "Fred" from component "Dancers" into the
variable "FredAstaire" from component "Astair": variable_1 must exist within
component_1, and variable_2 must exist within component_2. -->
<connection component_1="Dancers" component_2="Astaire">
<map_variables variable_1="Fred" variable_2="FredAstaire" />
</connection>
</model>
Interpretation of initial_value
attributes¶
The conditions under which initial values hold are (by design) not defined in a CellML model.
The
initial_value
attribute of avariable
element MUST either be a real number string, or a variable reference.If the
initial_value
attribute is a real number string, then it SHALL be interpreted as a statement that the variable on which the attribute appears is equal to that real number value when the initial values hold.If the
initial_value
attribute is a variable reference, then it SHALL be interpreted as a statement that the variable on which the attribute appears is equal to the referenced variable when the initial values hold.
See more
Cycles within initial values
As with other places, it’s possible to set initial conditions which are valid in syntax but lacking in sense. The examples below are technically valid CellML, but they will not lead to meaningful models.
<component name="cyclical_initialisation" >
<variable name="A" initial_value="B" units="dimensionless"/>
<variable name="B" initial_value="A" units="dimensionless"/>
</component>
<component name="self_initialisation" >
<variable name="C" initial_value="C" units="dimensionless"/>
</component>
Best practice for constants, variables, and initial conditions
A
variable
whose value needs to be set for only the beginning of a simulation is initialised using theinitial_value
attribute.This is most frequently used for state variables (those whose value is found by solving a differential equation).
It may also be used for variables whose values will be reset during the course of the simulation. Please see The reset element section for details.
It’s possible - but not recommended - to use a variable reference with the
initial_value
attribute. This option remains in CellML 2.0 only to provide ease of migration from CellML 1.1 models, and may be discontinued in future versions.
A
variable
whose value is constant throughout the simulation is best set within themath
block, rather than via theinitial_value
attribute. This is so that its value will be held to be true throughout the simulation, rather than only the beginning.A
variable
which is not a state variable, and whose value changes during the simulation does not require initialisation; simply include it in amath
block so it can be evaluated.
The following example shows a model for counting games like hide and seek, where the first section shows an older format and the second section shows a better practice for CellML 2.0 models.
<!-- Childhood games involving counting down. -->
<model name="games">
<component name="hide_and_seek">
<variable name="countdown_start" units="second" initial_value="100"/>
<variable name="counter" units="second" initial_value="countdown_start" />
<variable name="time" units="second" />
<math>
<apply><eq/>
<ci>counter</ci>
<apply><minus/>
<ci>countdown_start</ci>
<ci>time</ci>
</apply>
</apply>
</math>
</component>
<component name="hiding_games">
<variable name="time" units="second" />
</component>
<component name="sardines" />
<!-- Creating a generic component to hold global variables like time. -->
<component name="parameters">
<variable name="time" units="second" initial_value="0" />
</component>
<!-- Encapsulating the games into the hiding_games component. -->
<encapsulation>
<component_ref component="hiding_games">
<component_ref component="hide_and_seek"/>
<component_ref component="sardines"/>
</component_ref>
</encapsulation>
<!-- Connect the time variable into the other components. -->
<connection component_1="parameters" component_2="hiding_games">
<map_variables variable_1="time" variable_2="time" />
</connection>
<connection component_1="hiding_games" component_2="hide_and_seek">
<map_variables variable_1="time" variable_2="time" />
</connection>
</model>
This is valid CellML and will work as expected, but it uses a constant (the initial_value
on the countdown_start
variable) embedded within the deepest level of the encapsulation, which makes it more difficult to restart the game from different countdown points.
A better way to organise the model is shown below, annotated with the differences as appropriate.
<model name="games">
<component name="hide_and_seek">
<!-- Remove the initial_values from encapsulated component, move to the "parameters" component. -->
<variable name="countdown_start" units="second" />
<variable name="counter" units="second" />
<variable name="time" units="second">
<math>
<apply><eq/>
<ci>counter</ci>
<apply><minus/>
<ci>countdown_start</ci>
<ci>time</ci>
</apply>
</apply>
</math>
</component>
<component name="sardines"/>
<!-- Define (or import) a top-level component used for setting all parameters, constants, and initial values. -->
<component name="parameters">
<variable name="time" units="second" />
<!-- Move the initialisation of the countdown initial value into this top-level component. -->
<variable name="hide_and_seek_start" initial_value="100" />
</component>
<!-- Add a new transfer variable throughout the encapsulation hierarchy. -->
<component name="hiding_games">
<variable name="time" units="second" />
<variable name="hide_and_seek_start" units="second" />
</component>
<encapsulation>
<component_ref component="hiding_games">
<component_ref component="hide_and_seek"/>
<component_ref component="sardines"/>
</component_ref>
</encapsulation>
<!-- Connect the initialisation variable thoughout the encapsulation hierarchy. -->
<connection component_1="parameters" component_2="hiding_games">
<map_variables variable_1="time" variable_2="time" />
<map_variables variable_1="hide_and_seek_start" variable_2="hide_and_seek_start">
</connection>
<connection component_1="hiding_games" component_2="hide_and_seek">
<map_variables variable_1="time" variable_2="time" />
<map_variables variable_1="hide_and_seek_start" variable_2="countdown_start" />
</connection>
</model>
Moving the initialisation out of the encapsulation hierarchy and into a top-level component allows us to more easily adjust the parameters of the game, as well as making its use more modular so that it can be shared with others.
Effect of units
on a variable
¶
The target of the
units
attribute on a variable is referred to as the “variable units”, and the corresponding unit reduction (see 3.3 Interpretation of units elements) is referred to as the “variable unit reduction”.
See more
Understanding variables and their units
The pairing of variables with units is distinct from every other relationship in CellML in that sometimes it matters, and sometimes it doesn’t. To better understand why this is, we first have to understand the ideas of reusability and modularity that prompted the design of encapsulation.
Each component in a CellML model is a package. That package may in turn contain other packages too, but each one is intended to represent an idea, a functionality, a black-boxed thing which can then be passed around and reused as needed.
Now think about a component from the perspective of another modeller who wants to reuse your component in their model:
When variables are passed between components (through equivalent variables) the units of those variables must be checked for consistency; the external modeller does not necessarily have knowledge of the inner workings of the black-box component, only the variables it passes to and fro across the boundaries. There are examples and further details available in 3.10 Interpretation of map_variables elements.
When variables are created to operate within a component (its local mathematics) their units are not checked; the modeller does have knowledge of the inner workings, and can control and interpret them as needed. There are examples and further details available in 3.8.3 in
{number} {name}
.
Thus, CellML deems it important for the component border crossings to have as much information as possible (that is: the units and variable pairs), yet permits modellers the flexibility to make their own decisions about units within components.
Interpretation of math
elements¶
The following
component
elements SHALL, for the purposes of this specification, be “pertinent component elements”:All
component
elements in the top-level CellML infoset for the CellML model;All
component
elements referenced byimport component
elements (see 3.1 Interpretation of import elements) in the top-level CellML infoset; andAll
component
elements which are descendants in the encapsulation digraph (see 3.9 Interpretation of encapsulation elements) of a pertinentcomponent
element.
See more
What is a “pertinent component”?
Pertinent components are those which together form the entirety of the model.
They could be locally defined within the model
itself, imported from a separate file, or a dependency within the encapsulated set of an imported component.
The example below describes a game of cricket in the backyard of a boy called Tom (defined locally).
He imports a boy called Harry from next door, but Harry’s dog Dick comes along too as an implicit import because the component DickTheDog
is encapsulated as a child of the component Harry
in the Neighbours.cellml
file.
All three components Tom
, DickTheDog
, and Harry
are “pertinent” to the BackyardCricket
model.
The component George
, also in the Neighbours.cellml
file is not pertinent, as it is not within the encapsulated set of the imported component Harry
.
file: MyHouse.cellml
└─ model: BackyardCricket
└─ component: FirstGame
├─ component: Tom (locally defined)
└─ component: Harry <╴╴╴╴╴╴╴╴╴╴╴╴┐
└─ component: DickTheDog ╷
explicitly importing Harry will
file: Neighbours.cellml implicitly import DickTheDog
└─ model: HarrysHouse ╵
├─ component: Harry ╴╴╴╴╴╴╴╴╴╴╴╴┬╴╴╴╴┘
│ └─ component: DickTheDog ╴╴╴╴┘
└─ component: George
See CellML syntax example
In file: MyHouse.cellml
<model name="BackyardCricket" >
<!-- Pertinent: A locally defined component. -->
<component name="Tom" />
<!-- Pertinent: An explicitly imported component. -->
<import href="Neighbours.cellml">
<component component_ref="Harry" name="Harry" />
</import>
<!-- Pertinent: Another locally-defined component. -->
<component name="FirstGame" />
<!-- The local encapsulation structure does not affect which components are pertinent. -->
<encapsulation>
<component_ref component="FirstGame" >
<component_ref component="Tom" />
<component_ref component="Harry" />
</component_ref>
</encapsulation>
</model>
In file: Neighbours.cellml
<model name="HarrysHouse" >
<component name="Harry" />
<!-- Pertinent: An implicitly imported component, pertinent because of its presence
in the encapsulated set of an imported component. -->
<component name="DickTheDog" />
<!-- Not pertinent: George is not a pertinent component item to the
BackyardCricket model as it is neither explicitly nor implicitly imported. -->
<component name="George" />
<!-- The encapsulation set means that DickTheDog is a pertinent component item,
as it is imported at the same time as the component Harry is imported. -->
<encapsulation>
<component_ref component="Harry" >
<component_ref component="DickTheDog" />
</component_ref>
</encapsulation>
</model>
After we know which components are pertinent, we can retrieve their mathematical contents (i.e.: the pertinent components’ math
elements) and use these in the broader BackyardCricket model.
Every MathML element in the CellML model which appears as a direct child of a MathML
math
element, which in turn appears as a child of a pertinentcomponent
element, SHALL be treated, in terms of the semantics of the mathematical model, as a statement which holds true unconditionally.
See more
Understanding how the mathematics works
The mathematics of a mathematical model is a collection of statements which are held to be true at all times.
These are distinct from initial conditions of a model (specified using the initial_value
attribute on variable
elements) which are only true initially.
You can read more about initialisation in 3.6 Interpretation of initial_value attributes page and in the section below this one.
The collection of mathematical statements in a CellML model is the set of children of all math
elements inside its “pertinent components” (as explained in the previous block).
The example from the previous point is extended below in pseudocode, with the full CellML code beneath the link below.
The final output from the model - the total runs scored - is found by reducing all of the math
elements from all pertinent components in the model, whether or not those components interact. In this example, the same mathematical situation could be written:
where \(r\) is the number of runs, and \(t\) is time.
model: BackyardCricket
│
└─ component: FirstGame
│ ├─ variable: dicks_runs <╴╴╴╴╴╴┐
│ ├─ variable: harrys_runs <╴╴┐ ╷
│ ├─ variable: toms_runs <╴┐ ╷ ╷
│ ├─ variable: time ╷ ╷ ╷
│ └─ math: total_runs = toms_runs + dicks_runs + harrys_runs
│ ╵ ╵ ╵
├─ component: Tom ╵ ╵ ╵
│ ├─ variable: runs ╴╴╴╴╴╴╴┘ ╵ ╵
│ └─ math: runs = 99 ╵ ╵ equivalent
│ ╵ ╵ variables
└─ component: Harry (imported) ╵ ╵
│ ├─ variable: runs ╴╴╴╴╴╴┘ ╵
│ ├─ variable: time ╵
│ ├─ variable: dicks_runs ╴╴╴┤
│ └─ math: runs = 10*time ╷
│ ╷
└─ component: DickTheDog ╷
├─ variable: runs ╴╴╴╴╴╴╴╴┘
└─ math: runs = 0
See CellML syntax example
In file: MyHouse.cellml
<model name="BackyardCricket" >
<!-- The local component Tom now has a score, measured by the variable "runs".
This score is constant for all of time. Tom will never get his century! -->
<component name="Tom">
<variable name="runs" units="dimensionless" />
<math>
<apply><eq/>
<ci>runs</ci>
<cn cellml:units="dimensionless">99</cn>
</apply>
</math>
</component>
<import href="Neighbours.cellml">
<component component_ref="Harry" name="Harry" />
</import>
<!-- The total tally for the game is stored in the variable "total". -->
<component name="FirstGame">
<variable name="total" units="dimensionless" />
<variable name="toms_runs" units=" dimensionless" />
<variable name="harrys_runs" units=" dimensionless" />
<variable name="dicks_runs" units=" dimensionless" />
<math>
<apply><eq/>
<ci>total</ci>
<apply><plus/>
<ci>toms_runs</ci>
<ci>harrys_runs</ci>
<ci>dicks_runs</ci>
</apply>
</apply>
</math>
</component>
<!-- Connections to report the runs from each player are established. -->
<connection component_1="FirstGame" component_2="Tom" >
<map_variables variable_1="toms_runs" variable_2="runs" />
</connection>
<!-- Since component "DickTheDog" is too distant in the encapsulation structure to be
visible to the "FirstGame" component, any runs scored by the dog must be passed
through Harry's component. -->
<connection component_1="FirstGame" component_2="Harry" >
<map_variables variable_1="harrys_runs" variable_2="runs" />
<map_variables variable_1="dicks_runs" variable_2="dicks_runs" />
</connection>
<encapsulation>
<component_ref component="FirstGame" >
<component_ref component="Tom" />
<component_ref component="Harry" />
</component_ref>
</encapsulation>
</model>
In file: Neighbours.cellml
<model name="HarrysHouse" >
<component name="DickTheDog">
<variable name="runs" units="dimensionless" />
<math>
<!-- This statement sets DickTheDog's score to 0 for all time.
He's a dog: potentially a good outfielder, but a terrible batsman. -->
<apply><eq/>
<ci>runs</ci>
<cn cellml:units="dimensionless">0</cn>
</apply>
</math>
</component>
<component name="Harry">
<variable name="time" units="minute" />
<variable name="runs" units="dimensionless" />
<variable name="dicks_runs" units="dimensionless" />
<math>
<!-- This statement represents DickTheDog running away with the ball,
enabling Harry to score an ever-increasing number of runs. -->
<apply><eq/>
<ci>runs</ci>
<apply><times/>
<cn cellml:units="per_minute">10</cn>
<ci>time</ci>
</apply>
</math>
</component>
<!-- This is not a pertinent component to the BackyardCricket model. -->
<component name="George" />
<!-- A connection is established between Harry and DickTheDog to enable sharing of their run tally. -->
<connection component_1="Harry" component_2="DickTheDog" >
<map_variables variable_1="dicks_runs" variable_2="runs" />
</connection>
...
</model>
Understanding how and when the mathematics doesn’t work
It’s possible to write valid CellML that does not represent valid mathematics.
You can think of this like correctly spelling a set of words which together do not form a meaningful sentence.
Some examples of valid versus valid-but-nonsense math
elements’ contents are shown below.
Simple over-definition is valid, but will result in behaviour that is hard to interpret meaningfully:
Complicated over-definition is likewise valid:
Redundant information is valid, but (well) redundant:
Under-definition at a localised component level is both valid and useful, as you may need to connect to other components in order to know the value of the variables the maths statements are using. Models which overall have insufficient definition are also valid, but clearly won’t be useful or solvable:
Unsolvable models and “bad” maths is valid CellML:
Conflicting information arising from initialising variables which are not state variables will have an outcome which depends on how the implementation software interprets the condition. It is not invalid CellML, but - as with other forms of over-definition - may not result in the same interpretation between software implementations.
Units referenced by a
units
attribute SHALL NOT affect the mathematical interpretation of the CellML model.
See more
Understanding how the units work
Within a component:
We know that units in real life make a big difference, but within a CellML component, they don’t.
Units in equations are provided to help the user find bugs, and each variable
element has to specify a corresponding units
element, but these combinations don’t affect the validity of the math
element.
They do make a difference to how your model may to be interpreted, and can help you to find errors or inconsistencies in your mathematical definitions.
Some examples are shown below.
Constants and variables in an equation have different units: this is not invalid CellML, but doesn’t make any mathematical sense.
<variable name="lunch" units="omelette" /> ... <apply><eq/> <ci>lunch</ci> <apply><plus/> <cn cellml:units="egg">2</cn> <cn cellml:units="cheese">5</cn> <cn cellml:units="milk">0.1</cn> </apply> </apply>
Exponents have units other than
dimensionless
: again, not invalid CellML, but mathematical nonsense.
<variable name="E" units="joule" /> <variable name="m" units="kilogram" /> <variable name="c" units="metres_per_second" /> ... <apply><eq/> <ci>E</ci> <apply><times/> <ci>m</ci> <apply></power> <ci>c</ci> <cn cellml:units="anything_not_dimensionless">2</cn> </apply> </apply> </apply>A complete list of the mathematically valid units for different MathML operations is available under the link below.
Show units guidelines for MathML operations
Units guidelines for MathML operations
eq
,neq
,gt
,lt
,geq
,leq
,and
,or
,xor
,not
The inputs to these operators should have equivalent units.
The result of these operators is not a number with a unit, but one of the logical constants
true
orfalse
. These constants can be used as the second ordinand of thepiece
operator, but cannot be used as input to operators expecting a numerical type.
piecewise
The inputs consist of
piece
andotherwise
elements which have units as described in those sections.The output of this operator has units given by the selected
piece
orotherwise
element child.
piece
, (otherwise
)
The first input may have any units.
The second input is a relational statement, which does not have units.
The output of each operator has the same units as their first inputs.
exp
,exponentiale
,ln
,log
,logbase
The input of each operator must have units of
dimensionless
.The output of each operator has units of
dimensionless
.
sin
,cos
,tan
,sec
,csc
,cot
,sinh
,cosh
,tanh
,sech
,csch
,coth
,arcsin
,arccos
,arctan
,arccosh
,arccot
,arccoth
,arccsc
,arccsch
,arcsec
,arcsech
,arcsinh
,arctanh
The input of each operator must have units of
dimensionless
.The output of each operator has units of
dimensionless
.
plus
,minus
,min
,max
The inputs of each operator must have equivalent units.
The output of each operator has the same units as its inputs.
abs
,floor
,ceiling
The inputs may have any units.
The output of each operator has the same units as its input.
times
The inputs may have any units.
The output has units given by the product of the units of the inputs. This product may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
divide
,rem
The inputs may have any units.
The output of each operator has units given by the quotient of the units on the first and second inputs. This quotient may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
power
The first input may have any units.
The second input must have units of
dimensionless
.The output has units given by the units of the first input raised to the power of the second input.
If the first input has units of
dimensionless
, the output units aredimensionless
as well.
root
, (degree
)
The first input may have any units.
The
degree
element, if present, must have units ofdimensionless
.The output has units given by the units on the first input raised to the reciprocal of the value of the
degree
qualifier element (the default value of which is 2.0).If the first input has units of
dimensionless
, the output units aredimensionless
as well.
diff
, (bvar
,degree
)
The input may have any units.
The output has units that are the quotient of the units of the input over the units of the term in the
bvar
qualifier element raised to the value of thedegree
qualifier element inside thebvar
qualifier element (the default value of which is 1.0). This quotient may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
Between components: Components were designed to promote modularity and reuse of models, so it’s important that those re-users understand what they’re getting into. This is why equivalent variables (those connected across components) must have the same unit reduction, so that whatever the inner workings of a component are, the external users of that component are able to interpret them correctly.
The only situation in which units
items are compared to one another is between equivalent variables, i.e.: the variable_1
and variable_2
attributes of a map_variables
element.
Here, both of the variable
elements referenced must have the same unit reduction, though not necessarily the same multiplication factor.
Some examples of these are shown below.
Any custom or built-in units with differing scaling factors between connected variables: valid, as the unit reduction is the same, but the resulting mathematics will need to be interpreted carefully!
model: DCUniverse ├─ component: Metropolis │ └─ variable: Superman (units = megapowers) <╴╴┐ │ ╷ │ connected variables ├─ component: Smallville ╵ │ └─ variable: ClarkKent (units = micropowers) ╴┘ │ └─ units: powers ├─ units: micropowers = 0.000001*powers └─ units: megapowers = 1,000,000*powersSee CellML syntax
<model name="DCUniverse"> <!-- Defining a custom base unit called "powers". --> <units name="powers" /> <!-- Creating the derived custom units with different prefixes, mega and micro. --> <units name="megapowers" > <unit units="powers" prefix="mega" /> </units> <units name="micropowers"> <unit units="powers" prefix="micro" /> </units> <!-- The variable "Superman" in component "Metropolis" has units of "megapowers". --> <component name="Metropolis"> <variable name="Superman" units="megapowers" /> </component> <!-- The variable "ClarkKent" in component "Smallville" has units of "micropowers". --> <component name="Smallville"> <variable name="ClarkKent" units="micropowers" /> </component> <!-- The connection is valid, because the unit reduction is the same, even though the multiplication factor between the two variables is different. --> <connection component_1="Metropolis" component_2="Smallville"> <map_variables variable_1="Superman" variable_2="ClarkKent" /> </connection> </model>
Any custom of built-in units with differing unit reduction tuples between connected variables: invalid, as it contradicts point 3.10.6 in 3.10 Interpretation of map_variables elements. Please see the third informative block in 3.3 Interpretation of units elements section for more discussion and examples of unit reductions.
model: DCUniverse ├─ component: FarFromKryptonite │ └─ variable: Superman (units = megapowers) <╴╴╴╴┐ │ ╷ │ connection is now invalid ├─ component: NearToKryptonite ╵ │ └─ variable: ClarkKent (units = marshmallow) ╴╴╴┘ │ ├─ units: powers │ └─ units: megapowers = 1,000,000*powers │ └─ units: marshmallowSee CellML syntax
<model name="DCUniverse"> <units name="powers" /> <units name="megapowers" > <unit units="powers" prefix="mega" /> </units> <!-- Creating a new base unit called "marshmallow".--> <units name="marshmallow" /> <!-- The variable "Superman" in component "FarFromKryptonite" has units of "megapowers". --> <component name="FarFromKryptonite"> <variable name="Superman" units="megapowers" /> </component> <!-- The variable "ClarkKent" in component "NearToKryptonite" has units of "marshmallow". --> <component name="NearToKryptonite"> <variable name="ClarkKent" units="marshmallow" /> </component> <!-- The connection is invalid, because the unit reduction not the same. --> <connection component_1="FarFromKryptonite" component_2="NearToKryptonite"> <map_variables variable_1="Superman" variable_2="ClarkKent" /> </connection> </model>
In summary, the only place in which units can cause validation errors related to variables is between equivalent variables (variables connected using connection
and map_variables
elements):
x
[Volts] equivalent toy
[Amps] : invalid, conflicting unit reductions;x
[Volts] equivalent toy
[millivolts] : valid, unit reductions are the same even though the scaling factor is different;in the
math
elementx
[Volts] =y
[Amps]: valid (but nonsense);in the
math
elementx
[Volts] = 3 [Amps]: valid (but nonsense).
Interpretation of encapsulation
elements¶
For the purposes of this specification, there SHALL be a conceptual “encapsulation digraph” in which there is exactly one node for every component in the CellML model.
If a
component_ref
element appears as a child of anothercomponent_ref
element, then there SHALL be an arc in the encapsulation digraph, and that arc SHALL be from the node corresponding to the component referenced by the parentcomponent_ref
element, and to the node corresponding to the component referenced by the childcomponent_ref
element.
See more
You can think of an encapsulation structure as a tree. The model is the tree’s trunk, and each component at the top-level of the model is a branch. Subsequent generations of branches can stem from any component, but no two branches can recombine or belong to more than one parent, as this would create a loop. Any component not listed inside the encapsulation is a top-level component (a branch off the trunk).
An encapsulation hierarchy is specified using a single encapsulation
element, and any number of generations of component_ref
children.
Where no encapsulation
element is present, all component
elements have the same level; they branch off the model
-trunk.
Some examples of valid and invalid encapsulation structures are shown below.
<!-- Valid encapsulation structure. This will give the arrangement of:
- grandad
- father
- child
- aunt
- orphan
Because the component named "orphan" is not included in the encapsulation
it will stay at the top level of the model. -->
<model name="I_am_a_valid_model">
<component name="grandad"/>
<component name="aunt"/>
<component name="father"/>
<component name="child"/>
<component name="orphan">
<encapsulation>
<component_ref component="grandad">
<component_ref component="aunt"/>
<component_ref component="father">
<component_ref component="child"/>
</component_ref>
</component_ref>
</encapsulation>
</model>
<!-- Invalid: More than one encapsulation is not permitted. -->
<model name="too_many_encapsulations">
<component name="parent1"/>
<component name="child1"/>
<component name="parent2"/>
<component name="child2"/>
<encapsulation>
<component_ref component="parent1">
<component_ref component="child2"/>
</component_ref>
</encapsulation>
<encapsulation>
<component_ref component="parent2">
<component_ref component="child2"/>
</component_ref>
</encapsulation>
</model>
<!-- Invalid: A component cannot appear more than once in an encapsulation. -->
<model name="duplicated_component_ref">
<component name="parent"/>
<component name="child"/>
<encapsulation>
<component_ref component="parent">
<component_ref component="child">
<component_ref component="parent"/>
</component_ref>
</component_ref>
</encapsulation>
</model>
<!-- Valid, but redundant: An encapsulation can be empty, but this is the default
condition so its inclusion alters nothing. -->
<model name="empty_encapsulation">
<component name="parent"/>
<component name="child"/>
<encapsulation>
</encapsulation>
</model>
<!-- Valid, but redundant: An encapsulation must have a minimum of two levels of children
to affect the model's structure. This still represents the default condition. -->
<model name="duplicated_component_ref">
<component name="parent"/>
<component name="child"/>
<encapsulation>
<component_ref component="parent">
<!-- There has to be a child here or the parent is not a parent. -->
</component_ref>
</encapsulation>
</model>
The “encapsulated set” for a component A SHALL be the set of all components B such that there exists an arc in the encapsulation digraph from the node corresponding to A to the node corresponding to B.
The “encapsulation parent” for a component A SHALL be the component corresponding to the node which is the parent node in the encapsulation digraph of the node corresponding to A. A component SHALL NOT appear as child of more than one encapsulation parent.
The “sibling set” for a component A SHALL be the set of all components which have the same encapsulation parent as A, or in the case that A has no encapsulation parent, SHALL be the set of all components which do not have an encapsulation parent.
See more
In the informative block above we used the analogy of a tree to describe the encapsulation structure, but the language around it is closer to a family tree in which there are only single parents allowed. With this in mind, the points above become clear.
3.9.3 defines the “encapsulation set” of a component as its direct component children.
3.9.4 makes clear that there can only be single parents in this family tree.
3.9.5 defines siblings as those
component
elements which share a parent, be that parent acomponent
element or themodel
element itself.3.9.6 defines the “hidden set” of any
component
as those othercomponent
elements which are neither the parent, the children, nor the siblings of that currentcomponent
element.
These distinctions become important when considering the kind of connection
elements which may be formed, and in determining the interface_type
attribute values which are available to a component’s variable
children.
The example below illustrates the extended family tree from the 1980s TV show, The Beverly Hillbillies.
model: TheBeverlyHillbillies
├─ component: GrannyMoses
├─ component: MissJane
└─ component: ClampettFamily
├─ component: LukeClampett
│ ├─ component: MyrtleClampett
│ └─ component: JedClampett
│ └─ component: EllyMayClampett
└─ component: AmosClampett
└─ component: PearlBodine
├─ component: JethroBodine
└─ component: JethrineBodine
See CellML syntax
<model name="TheBeverlyHillbillies">
<!-- Note that the first two components here are not listed inside the
encapsulation. They are, by default, siblings of each other,
as well as of the root component (ClampettFamily) of the
encapsulation structure. -->
<component name="GrannyMoses" />
<component name="MissJane" />
<component name="ClampettFamily" />
<component name="LukeClampett" />
<component name="AmosClampett" />
<component name="MyrtleClampett" />
<component name="JedClampett" />
<component name="EllyMayClampett" />
<component name="PearlBodine" />
<component name="JethroBodine" />
<component name="JethrineBodine" />
<encapsulation>
<component_ref component="ClampettFamily">
<component_ref component="LukeClampett">
<component_ref component="MyrtleClampett">
</component_ref>
<component_ref component="JedClampett">
<component_ref component="EllyMayClampett"/>
</component_ref>
</component_ref>
<component_ref component="AmosClampett">
<component_ref component="PearlBodine">
<component_ref component="JethroBodine"/>
<component_ref component="JethrineBodine"/>
</component_ref>
</component_ref>
</encapsulation>
</model>
In this example, we can see that the encapsulation set (or direct children) of component PearlBodine
are the twins JethroBodine
and JethrineBodine
.
Similarly, LukeClampett
is the parent of MyrtleClampett
and JedClampett
.
Several sets of siblings are fairly easy to spot:
JethroBodine
andJethrineBodine
,LukeClampett
andAmosClampett
, andMyrtleClampett
andJedClampett
.
Other siblings that are not as clear at first glance are GrannyMoses
, MissJane
, and the placeholder ClampettFamily
, by virtue of their common parent, TheBeverlyHillbillies
model itself.
See more
Before two variable
elements can be connected or mapped to one another, two set of rules must be followed.
The first rule is that the variables’ parent component
elements must not be hidden from one another (as stated in 3.9.7), and the second (found in 3.10.9-10) is that the interface_type
attributes of the variables must not exclude their connection either.
Understanding hidden sets and connections
It’s easier to define hidden components by defining those which are not hidden first.
Basically, one degree of separation is all that is “seen” by any component.
This means that parent components can see their children, and children their parents.
Sibling components (including those who are top-level children of the model
element) are visible to one another as well.
Components in any other relationships are too distant to be visible, and are therefore hidden from each other.
Reusing the same example as earlier, we can see that:
LukeClampett
is hidden fromEllyMayClampett
(grandfather/grandchild)AmosClampett
is hidden fromMyrtleClampett
(uncle/niece)PearlBodine
is hidden fromJedClampett
(cousins)GrannyMoses
is hidden fromLukeClampett
(great-aunt/great-nephew)
model: TheBeverlyHillbillies
├─ component: GrannyMoses
├─ component: MissJane
└─ component: ClampettFamily
├─ component: LukeClampett
│ ├─ component: MyrtleClampett
│ └─ component: JedClampett
│ └─ component: EllyMayClampett
└─ component: AmosClampett
└─ component: PearlBodine
├─ component: JethroBodine
└─ component: JethrineBodine
<!-- None of the following connections are possible as their
components are hidden from one another. -->
<!-- Grandfather and grandchild. -->
<connection component_1="LukeClampett" component_2="EllyMayClampett" />
<!-- Uncle and niece. -->
<connection component_1="AmosClampett" component_2="MyrtleClampett" />
<!-- Cousin and cousin. -->
<connection component_1="PearlBodine" component_2="JedClampett" />
<!-- Great-aunt and great-nephew. -->
<connection component_1="GrannyMoses" component_2="LukeClampett" />
The second rule above addresses the restrictions around which variable
elements are able to access one another.
This is a little more complicated, and explained in more detail in the informative block in 3.10 Interpretation of map_variables elements.
Interpretation of map_variables
elements¶
For the purposes of this specification, the conceptual “variable equivalence network” SHALL be an undirected graph with one node for every
variable
element in the CellML model.The arcs of this graph SHALL be equivalences defined in the CellML model.
See more
Understanding the terminology
The idea of component modularity and separateness is helpful in organising models and reusing parts of them, but only if it’s also possible to share information between the distinct components.
This is the goal of “variable equivalence”, and requires the combined mechanisms of connection
elements (to connect components) and map_variables
elements (to connect their variables).
Several different words have been used to describe what is essentially this one process: equivalent variables, the connected variable set, mapped variables, etc.
All of these mean the same thing: that the variables in the set act as a single agent throughout the model.
They may have different local names within a component, but they will have the same value everywhere they exist.
Thus there are two ways in which variables are related to one another.
The first is through the mathematical equations as specified in intra-component math
elements; the second is through variable equivalences as specified in inter-component connection
and map_variables
elements.
Both the connection
and map_variables
elements are undirected.
There is no update direction or hierarchy; they all represent, instantaneously, the same thing.
For each
map_variables
element present in the CellML model, we define variables A and B for use in the rules in this section as follows:Variable A SHALL be the variable referenced by the encompassing
connection
element’scomponent_1
and thismap_variables
element’svariable_1
attribute; andVariable B SHALL be the variable referenced by the encompassing
connection
element’scomponent_2
and thismap_variables
element’svariable_2
attribute.
For every
map_variables
element present in the CellML model, there SHALL be an arc in the variable equivalence network.One endpoint of the arc in the variable equivalence network SHALL be the node corresponding to variable A; and
One endpoint of the arc in the variable equivalence network SHALL be the node corresponding to variable B.
See more
Understanding the players
You can think of the previous two points as defining an address using a street name and number.
Since streets (components) have lots of houses (variables) they all need different numbers (variable names) in that street.
And since lots of streets (components) have houses (variables) with the same number (name), we need both the street name and the house number in order to locate a house properly.
This is the purpose of the component_1
and component_2
attributes of connection
elements (to define the respective street (component) names), and the variable_1
and variable_2
attributes of each connection
element’s map_variables
element (to define the respective house number (variable name)).
Thus the “equivalent variable network” is a collection of unique variables (each specified a component and a variable name), which will be treated as the same variable throughout the model.
Note that we use the term “network” here as it best describes the process by which variable equivalence is constructed, even if its final interpretation is not a network, but rather a set.
CellML models MUST NOT contain any pair of
map_variables
elements which duplicates an existing arc in the variable equivalence network.The variable equivalence network MUST NOT contain any cycles.
See more
Understanding the rules
As well as the syntax definitions above, there are rules regarding which variables are able to be connected to one another too.
Both points 3.10.4 and 3.10.5 address a similar issue: that the “network” of variable equivalence must not contain any cycles (a connection such that A-B-A is just a mini cycle after all).
In the model below there are three sets of variables which have equivalent values, and it is the modeller’s desire that they be able to use them interchangably in each language whilst maintaining their value throughout. There are two situations which would render the model invalid if these variables were mapped incorrectly, as shown below.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een
│ ├─ variable: twee
│ ├─ variable: drie
│ └─ variable: vier
├─ component: Maori
│ ├─ variable: tahi
│ ├─ variable: rua
│ ├─ variable: toru
│ └─ variable: wha
└─ component: French
├─ variable: un
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<model name="LearningToCount">
<component name="Dutch">
<variable name="een" />
<variable name="twee" />
<variable name="drie" />
<variable name="vier" />
</component>
<component name="Maori">
<variable name="tahi" />
<variable name="rua" />
<variable name="toru" />
<variable name="wha" />
</component>
<component name="French">
<variable name="un" />
<variable name="deux" />
<variable name="trois" />
<variable name="quatre" />
</component>
</model>
Firstly, duplicated connections are not permitted because they create a mini-cycle of two variables. If an Anglophone is given a definition of een to mean tahi, and tahi to mean een, they are none the wiser.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een <╴╴╴┬╴╴╴┐
│ ├─ variable: twee ╷ ╷
│ ├─ variable: drie duplicate mapping
│ └─ variable: vier causes a mini-cycle
├─ component: Maori ╵ ╵
│ ├─ variable: tahi <╴╴┴╴╴╴┘
│ ├─ variable: rua
│ ├─ variable: toru
│ └─ variable: wha
└─ component: French
├─ variable: un
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<!-- Valid: First define the two components using a connection ... -->
<connection component_1="Dutch" component_2="Maori">
<!-- ... and then define the mapping between two variables within
those two components. -->
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<!-- Invalid: Duplicated mappings are not allowed. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<!-- Invalid: Duplicated connections are not allowed. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<connection component_1="Maori" component_2="Dutch">
<map_variables variable_1="tahi" variable_2="een" />
...
</connection>
Secondly, any form of cyclical definition is invalid, as it leaves the mathematical model underdefined. So our Anglophone could be also told that drie means trois, trois means toru, and toru means drie, but unless one of them is nailed down to an actual value somewhere, the model remains under-defined.
model: LearningToCount
├─ component: Dutch
│ ├─ variable: een <╴╴╴╴┐<╴╴╴╴╴╴╴╴┐
│ ├─ variable: twee ╷ ╷
│ ├─ variable: drie cycle created
│ └─ variable: vier ╷ ╷
├─ component: Maori ╷ ╷
│ ├─ variable: tahi <╴╴╴┘<╴╴╴┐ ╷
│ ├─ variable: rua ╷ ╷
│ ├─ variable: toru ╷ ╷
│ └─ variable: wha ╷ ╷
└─ component: French ╷ ╷
├─ variable: un <╴╴╴╴╴╴╴╴╴╴┘<╴╴╴┘
├─ variable: deux
├─ variable: trois
└─ variable: quatre
See CellML syntax
<!-- Invalid: a cycle is created. -->
<connection component_1="Dutch" component_2="Maori">
<map_variables variable_1="een" variable_2="tahi" />
...
</connection>
<connection component_1="Maori" component_2="French">
<map_variables variable_1="tahi" variable_2="un" />
...
</connection>
<connection component_1="French" component_2="Dutch">
<map_variables variable_1="un" variable_2="een" />
...
</connection>
For a given variable, the “available interfaces” SHALL be determined by the value of the
interface
attribute on the correspondingvariable
element as follows:A value of
public
specifies that the variable has a public interface;A value of
private
specifies that the variable has a private interface;A value of
public_and_private
specifies that the variable has both a public and a private interface;A value of
none
specifies that the variable has no interface; orIf the
interface
attribute is absent, then the variable has no interface.
The “applicable interfaces” for variables A and B in components AA and BB respectively SHALL be defined as follows:
When component AA is in the sibling set of component BB (and vice versa), the applicable interface for both variables A and B SHALL be the public interface.
When component AA is in the encapsulated set of component BB, the applicable interface for variable A SHALL be the public interface, and the applicable interface for variable B SHALL be the private interface.
When component BB is in the encapsulated set of component AA, the applicable interface for variable B SHALL be the public interface, and the applicable interface for variable A SHALL be the private interface.
Note
For the avoidance of doubt, if components AA and BB are in each other’s hidden set, then there are no applicable interfaces for the variables A and B.
CellML models MUST only contain
map_variables
elements where the applicable interfaces for both variables are available.
See more
Understanding mappings and units
The only place in which valid units
items can cause a model to be invalid is between mapped variables.
Point 3.10.6 means that each variable within a map_variables
element must have an equivalent unit reduction.
Please see that section for more details.
For each
map_variables
element present in the CellML model, the variable unit reduction (see 3.7 Effect of units on a variable) of variable A MUST have an identical set of tuples to the variable unit reduction of variable B.Two sets of tuples SHALL be considered identical if all of the tuples from each set are present in the other, or if both sets are empty.
Two tuples are considered identical if and only if both the unit name and exponent of each tuple are identical.
Tuples differing by a multiplying factor in their unit reduction MUST be taken into account when interpreting the numerical values of the variables (see 3.3 Interpretation of units elements).
See more
Understanding interfaces
There are two hurdles to get past before variables can be mapped to one another.
The first is the relative position within the encapsulation hierarchy of the variable
elements’ parent component
elements (as discussed in 3.9 Interpretation of encapsulation elements, and the second is the value of the interface_type
attribute given to each variable
itself.
This means that even if two components are sufficiently close relatives that they can be connected, the modeller still has control at the individual variable level as to which of those relatives can have access.
The interface_type
attribute value choices are:
- public
(used by child components to reference their parent, or between siblings),
- private
(used by parent components to reference their children),
- public_and_private
(used when both the public
and private
interfaces are required), or
- none
, which is the default.
Which one(s) of these are deemed applicable for any variable
mapping is determined by the relationship between the their parent component
elements.
In the example below, Christopher Robin must assemble an average score of the mood of all of his friends in the Hundred Acre Wood.
He does not have access to all of their mood
scores directly, so must use mapped variables in order to create the average.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood
│ ├─ variable: average_mood_of_everyone
│ ├─ variable: roos_mood
│ ├─ variable: kangas_mood <╴╴╴╴╴┐
│ ├─ variable: eeyores_mood <╴╴╴┐╷
│ └─ variable: poohs_mood <╴╴╴╴┐╷╷
│ ╷╷╷
│ connections between these
│ components are possible, depending
│ on the variables' interfaces
│ ╵╵╵
├─ component: WinnieThePooh ╵╵╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴┘╵╵
├─ component: Eeyore ╵╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴╴┘╵
└─ component: Kanga ╵
│ ├─ variable: mood ╴╴╴╴╴╴╴╴╴╴┘
└─ component: Roo
└─ variable: mood ╴╴╴╴╴╴╴╴╴╴> This variable cannot be connected to
anything within the ChristopherRobin
component as its component is too distant.
At present, the connections above in dashed lines are possible, as long as the variables have interface types which support them.
One connection is not possible (yet): Christopher Robin doesn’t know Roo’s mood, because their components are too distant (grandparent/grandchild) to be directly connected.
We can add a utility variable roos_mood
to the Kanga
component in order to pass along its value to the ChristopherRobin
component.
We’ll also add interface types to the variables, and discuss their effects below.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood
│ ├─ variable: average_mood_of_everyone
│ ├─ variable: roos_mood (interface: public) <╴╴╴╴╴ D ╴╴╴╴╴╴╴╴╴╴╴╴┐
│ ├─ variable: kangas_mood (interface: none) <╴╴╴╴╴ C ╴╴╴╴┐ ╷
│ ├─ variable: eeyores_mood (interface: public) <╴╴ B ╴╴╴┐╷ ╷
│ └─ variable: poohs_mood (interface: public) <╴╴╴╴ A ╴╴┐╷╷ ╷
│ ╷╷╷ utility variable added so
├─ component: WinnieThePooh ╷╷╷ that Roo's mood can be passed
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷ down to Christopher Robin
├─ component: Eeyore ╷╷ ╵
│ └─ variable: mood ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷ ╵
└─ component: Kanga ╷ ╵
│ ├─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘ ╵
│ └─ variable: roos_mood (interface: private) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┤
└─ component: Roo ╷
└─ variable: mood (interface: public) ╴╴╴╴╴╴ E ╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="TheHouseAtPoohCorner">
<!-- Defining the components and local variables. -->
<component name="ChristopherRobin">
<variable name="my_mood" interface_type="none" units="mood_score" />
<variable name="average_mood_of_everyone" interface_type="none" units="mood_score" />
<variable name="roos_mood" interface_type="public" units="mood_score" />
<variable name="kangas_mood" interface_type="none" units="mood_score" />
<variable name="eeyores_mood" interface_type="public" units="mood_score" />
<variable name="poohs_mood" interface_type="public" units="mood_score" />
</component>
<component name="WinnieThePooh">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Eeyore">
<variable name="mood" units="mood_score" />
</component>
<component name="Kanga">
<variable name="mood" interface_type="public" units="mood_score" />
<!-- The utility variable roos_mood is included here so that it can pass
the value of mood in component Roo to roos_mood in component ChristopherRobin. -->
<variable name="roos_mood" interface_type="private" units="mood_score" />
</component>
<component name="Roo">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<!-- Defining connections and mapped variables. -->
<connection component_1="ChristopherRobin" component_2="WinnieThePooh">
<!-- Mapping A -->
<map_variables variable_1="poohs_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Eeyore">
<!-- Mapping B -->
<map_variables variable_1="eeyores_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Kanga">
<!-- Mapping C -->
<map_variables variable_1="kangas_mood" variable_2="mood" />
<!-- Mapping D -->
<map_variables variable_1="roos_mood" variable_2="roos_mood" />
</connection>
<connection component_1="Kanga" component_2="Roo">
<!-- Mapping E -->
<map_variables variable_1="roos_mood" variable_2="mood" />
</connection>
</model>
Mapping A is valid. The sibling components
WinnieThePooh
andChristopherRobin
havepublic
interfaces between theirmood
andpoohs_mood
variables respectively. This follows point 3.10.9.1 and is valid.Mapping B is not valid. By default an interface type is
none
, and since themood
variable in componentEeyore
does not specify one, no mappings are permitted. For that connection to exist, themood
variable must have an interface typepublic
.Mapping C is not valid. The variable
kangas_mood
has explicitly specified that no mappings are possible by using thenone
interface type. For this mapping to be valid, the type needs to bepublic
.Mapping D is not valid. Because they are sibling components, the variables in
ChristopherRobin
andKanga
must both have the interface type ofpublic
in order to be valid … but there’s a twist.Mapping E is currently valid, because variables in component
Kanga
can only access variables in its child componentRoo
with aprivate
interface. But if Mapping D is to be made valid, that same variable must maintain apublic
interface in order to access variables in its sibling componentChristopherRobin
. It is for this reason that thepublic_and_private
interface type exists. For Mappings D and E to be valid, the variableroos_mood
in componentKanga
must have an interface type ofpublic_and_private
.
The corrected model is shown below.
model: TheHouseAtPoohCorner
├─ component: ChristopherRobin
│ ├─ variable: my_mood (interface: none)
│ ├─ variable: average_mood_of_everyone (interface: none)
│ ├─ variable: roos_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐
│ ├─ variable: kangas_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷
│ ├─ variable: eeyores_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷╷
│ └─ variable: poohs_mood (interface: public) <╴╴╴╴╴╴╴╴╴╴╴╴╴╴┐╷╷╷
│ ╷╷╷╷
├─ component: WinnieThePooh ╷╷╷╷
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷╷
├─ component: Eeyore ╷╷╷
│ └─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘╷╷
└─ component: Kanga ╷╷
│ ├─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴ ╴╴╴╴┘╷
│ └─ variable: roos_mood (interface: public_and_private) <╴╴╴┤
└─ component: Roo ╷
└─ variable: mood (interface: public) ╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴╴┘
See CellML syntax
<model name="TheHouseAtPoohCorner">
<!-- Defining the components and local variables. -->
<component name="ChristopherRobin">
<variable name="my_mood" interface_type="none" units="mood_score" />
<variable name="average_mood_of_everyone" interface_type="none" units="mood_score" />
<variable name="roos_mood" interface_type="public" units="mood_score" />
<variable name="kangas_mood" interface_type="public" units="mood_score" />
<variable name="eeyores_mood" interface_type="public" units="mood_score" />
<variable name="poohs_mood" interface_type="public" units="mood_score" />
</component>
<component name="WinnieThePooh">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Eeyore">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<component name="Kanga">
<variable name="mood" interface_type="public" units="mood_score" />
<!-- The utility variable roos_mood is included here so that it can pass
the value of mood in component Roo to roos_mood in component ChristopherRobin. -->
<variable name="roos_mood" interface_type="public_and_private" units="mood_score" />
</component>
<component name="Roo">
<variable name="mood" interface_type="public" units="mood_score" />
</component>
<!-- Defining connections and mapped variables. -->
<connection component_1="ChristopherRobin" component_2="WinnieThePooh">
<map_variables variable_1="poohs_mood" variable_2="mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Kanga">
<map_variables variable_1="kangas_mood" variable_2="mood" />
<map_variables variable_1="roos_mood" variable_2="roos_mood" />
</connection>
<connection component_1="ChristopherRobin" component_2="Eeyore">
<map_variables variable_1="eeyores_mood" variable_2="mood" />
</connection>
<connection component_1="Kanga" component_2="Roo">
<map_variables variable_1="roos_mood" variable_2="mood" />
</connection>
</model>
The
variable
elements in a CellML model SHALL be treated as belonging to a single “equivalent variable set”.Each set of equivalent variables is the set of all
variable
elements for which the corresponding nodes in the variable equivalence network form a connected subgraph.Each set of equivalent variables represents one variable in the underlying mathematical model.
See more
Understanding mathematics
In an episode of Bill Watterson’s comic, Calvin and Hobbes, Calvin builds a duplicator machine and clones himself several times so that the clones can do his chores in different rooms of the house.
This is essentially the purpose of creating map_variables
elements: to enable the “clones” (the mapped variables) to be used in separate “rooms” (components) whilst really representing the same thing.
The first sentence in 3.10.11 explains this: Each variable
element in a CellML model SHALL be treated as belonging to a single “connected variable set”; or, while there are many “connected variable sets” in a model, any one variable
may belong to only one of them.
In a CellML model there are two mechanisms by which variables can relate to one another: through the mathematics in the math
elements, and through the mapping in the map_variables
elements.
In a mathematical model, there is only one mechanism: the maths itself.
There are no clones, no duplicates, no mappings.
Thus, the purely mathematical model is found by collapsing each set of mapped variables (cloned characters) onto a single unique variable (character), until the relationships between these unique variables no longer involve mapping (cloning) but only mathematics. In the end, Calvin does the same, and the world returns to (roughly) normal.
Interpretation of reset
elements¶
For the purposes of this section, we define the “reset variable” to be the variable referenced by a
reset
element’svariable
attribute, and the “test variable” to be the variable referenced by itstest_variable
attribute.Each
reset
element describes a change to be applied to the reset variable when specified conditions are met during the simulation of the model.
See more
Understanding reset variables and test variables
In the following example we want to model the position of an automatic vacuum cleaner as it deflects off two opposite walls in a room. The device follows a straight line until it encounters a wall, at which point it immediately switches direction and travels back to the other wall. We will use resets to model the interaction of the device with the wall, but before they’re added, we’ll start with a very simplistic model which describes the position of the device changing with time:
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position [metre], initially 0
├─ variable: width [metre], constant, 5
├─ variable: velocity [metre_per_second], initially 0.1
└─ math:
└─ ode(position, time) = velocity
See CellML syntax
<model name="CleaningTheHouse">
<component name="Roomba">
<!-- Variables should be initialised using the initial_value attribute. -->
<variable name="position" units="metre" initial_value="0" />
<variable name="velocity" units="metre_per_second" initial_value="0.1" />
<!-- Constants should be set in the math element so that they are true for all time. -->
<variable name="width" units="metre" />
<math>
<!-- Constant: the room is 5m wide. -->
<apply><eq/>
<ci>width</ci>
<cn cellml:units="metre">5</cn>
</apply>
<!-- Variable: the position of the device comes from solving the ODE. -->
<apply><eq/>
<diff>
<ci>position</ci>
<bvar>time</bvar>
</diff>
<ci>velocity</ci>
</apply>
</math>
</component>
</model>
Now let’s add a reset to this such that when the device reaches the opposite wall, its direction of travel is reversed.
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position
├─ variable: width
│
├─ variable: velocity
│ └─reset:
│ ├─ "when position equals width"
│ └─ "then go back the other way"
│
└─ math:
└─ ode(position, time) = velocity
Show CellML syntax
<reset variable="velocity" test_variable="position" order="1">
<!-- The "when" statement above is true when the test_variable
attribute equals the test_value statement: -->
<test_value>
<ci>width</ci>
</test_value>
<!-- The "then" statement above is defined by setting the
variable attribute to the reset_value statement: -->
<reset_value>
<cn cellml:units="metre_per_second">-0.1</cn>
</reset_value>
</reset>
The behaviour at the other end of the wall is discussed in the following section.
All
reset
elements SHALL be considered sequentially for the equivalent variable set (see 3.10 Interpretation of map_variables elements) to which the reset variable belongs.The sequence SHALL be determined by the value of the reset element’s
order
attribute, lowest (least positive / most negative) having priority.
See more
Understanding the reset order
CellML is designed to represent complicated model behaviour, and this includes the idea that a single variable might need to be reset based different kinds of behaviour; or, that more than one reset is permitted per variable.
Continuing the example from the previous block, we’ll now add the behaviour of the automatic vacuum cleaner when it reaches its starting position at the first side of the room.
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position
├─ variable: width
│
├─ variable: velocity
│ ├─ reset A: order = 1
│ │ ├─ "when position equals width"
│ │ └─ "then set negative velocity"
│ └─ reset B: order = 2
│ ├─ "when position equals start"
│ └─ "then set positive velocity"
│
└─ math:
└─ ode(position, time) = velocity
At present it’s clear from the conditions on the two resets (the position at the start and at the far wall) that they cannot occur simulataneously, but this is not always the case.
For this reason, every reset must specify an order
attribute which will be used as a tie-breaker in situations where more than one reset on a variable is active at the same time.
It’s also worth noting that because of the variable equivalence functionality, when we talk about “per variable” here, we’re really including all resets which directly (as above, through the same variable
attribute) or indirectly (where another variable in the same equivalent variable set is referenced) change a variable’s value.
To illustrate the idea of the equivalent variables and order, we’ll add a new component which represents the battery charge on the device. When the battery reaches a lower limit the machine will stop moving.
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position
├─ variable: width
├─ variable: battery_level [charge], initially 100
│
├─ variable: velocity
│ ├─ reset A: order = 1
│ │ ├─ "when position equals width"
│ │ └─ "then set negative velocity"
│ ├─ reset B: order = 2
│ │ ├─ "when position equals start"
│ │ └─ "then set positive velocity"
│ └─ reset C: order = -1
│ ├─ "when battery level is less than 10"
│ └─ "then stop"
│
└─ math:
├─ ode(position, time) = velocity
└─ ode(battery_level, time) = -abs(velocity)
Show CellML syntax
<model name="CleaningTheHouse">
<component name="Roomba">
<variable name="position" units="metre" />
<variable name="width" units="metre" />
<variable name="battery_level" units="charge" initial_value="100" />
<variable name="velocity" units="metre_per_second" initial_value="0.1" />
<!-- Reset A will set a negative velocity when the Roomba reaches
the opposite wall: -->
<reset variable="velocity" test_variable="position" order="1">
<test_value>
<ci>width</ci>
</test_value>
<reset_value>
<cn cellml:units="metre_per_second">-0.1</cn>
</reset_value>
</reset>
<!-- Reset B will set a positive velocity when the Roomba reaches
the starting wall: -->
<reset variable="velocity" test_variable="position" order="2">
<test_value>
<cn cellml:units="metre">0</cn>
</test_value>
<reset_value>
<cn cellml:units="metre_per_second">0.1</cn>
</reset_value>
</reset>
<!-- Reset C will stop the Roomba when its charge is 10. -->
<reset variable="velocity" test_variable="battery_level" order="-1">
<test_value>
<cn cellml:units="charge">10</cn>
</test_value>
<reset_value>
<cn cellml:units="metre_per_second">0</cn>
</reset_value>
</reset>
<math>
<!-- Setting the width of the room as a constant: -->
<apply>
<eq/>
<ci>width</ci>
<cn cellml:units="metre">5</cn>
</apply>
<!-- Simple ODE for position of the Roomba with time: -->
<apply>
<eq/>
<diff>
<ci>position</ci>
<bvar>time</bvar>
</diff>
<ci>velocity</ci>
</apply>
<!-- Simple ODE for charge of the Roomba with time: -->
<apply>
<eq/>
<diff>
<ci>battery_level</ci>
<bvar>time</bvar>
</diff>
<apply>
<times/>
<apply>
<abs/>
<ci>velocity</ci>
</apply>
<cn units:cellml="charge_second_per_metre">-1</cn>
</apply>
</apply>
</math>
</component>
<!-- Custom units needed: -->
<units name="metre_per_second">
<unit units="metre" />
<unit units="second" exponent="-1" />
</units>
<units name="charge"/>
<units name="charge_second_per_metre">
<unit units="charge" />
<unit units="metre_per_second" exponent="-1"/>
</units>
</model>
In order for the machine to be able to stop when the battery is low, reset C must always be able to trump either of the other two as the conditions of reaching a wall and having a low battery could occur at the same time. This is accomplished by using an order of -1, making it lower than the order values of the other two resets, which also illustrates the idea that orders can be negative numbers (where the most negative is the most “important”).
Enacting the reset algorithm
Behind the syntax of the resets is an algorithm which determines how they are interpreted. This algorithm is outlined below.
For each reset item, determine whether its test criterion (the “when” idea above) has been met.
If yes, the reset is said to be “active”.
If not, it is “inactive”.
Collect all active resets for a variable and its equivalent variables into a “variable active set”.
For each variable, select the lowest order reset from the variable active set and designate it “pending”.
Calculate, but do not apply, the update changes specified by each pending reset based on the current state of the model.
Apply the updates calculated in (4). This step means that the order in which the variables’ values are altered does not affect the overall behaviour of the resets, as all of the updates are based on the unchanged state of the system.
Test whether the set of variable values in the model has changed:
If yes, repeat the steps above from (1) using the updated values as the basis for the tests.
If not, continue the modelling process with the updated values.
Let’s apply this to the example and see how it works. Consider the state when the roomba has reached the other side of the room, and the battery level has fallen to 10.
Applying (1), both resets A and C are designated active.
Applying (2), both resets A and C explicitly reference the variable
velocity
, so are in the same active set for that variable.Applying (3), we select reset C as having the lower order within the active set, and call it pending.
Applying (4), we evaluate the new value for the velocity variable to be zero because of the pending reset C.
Applying (5), set the velocity to zero.
Applying (6), this loop would be checked through again, but with the same result. The second time through the loop, we exit as there would be no further changes to the variables’ values.
There are alternative ways of arranging resets which would have the same functional outcome. These are described in 5.1 Using resets.
The condition under which a reset occurs SHALL be defined by the equality of evaluation of the test variable and the evaluation of the MathML expression encoded in the
test_value
.When a reset occurs, the reset variable SHALL be set to the result of evaluating the MathML expression encoded in the
reset_value
.
See more
Understanding the test_value
and reset_value
elements
In the previous block we introduced a model which showed how both a low battery and an encounter with a wall could affect the velocity of the Roomba, and used the order
attribute to determine which reset was followed.
Now we’d like to make sure that the low-battery Roomba is only ever stopped at a wall, so that people don’t trip up on it.
Conditional statements are legal inside both the test_value
block and reset_value
blocks, so we can write this (excluding units) as:
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position
├─ variable: width
├─ variable: battery_level [charge], initially 100
│
├─ variable: velocity
│ ├─ reset A1: order = 1
│ │ ├─ "when IF position equals width AND battery level is more than 10"
│ │ └─ "then set negative velocity"
│ ├─ reset A2: order = 2
│ │ ├─ "when IF position equals width AND battery level is 10 or less"
│ │ └─ "then stop"
│ │
│ └─ reset B: order = 2
│ ├─ "when position equals start AND battery level is more than 10"
│ └─ "then IF battery is more than 10 set positive velocity ELSE stop"
│
└─ math:
├─ ode(position, time) = velocity
└─ ode(battery_level, time) = -abs(velocity)
In this situation, reset A1 is only ever active when there is sufficient battery to change direction. This means that we’ve had to add a second reset A2 that tests for when the far wall is encountered and the battery is low. In contrast, similar behaviour is found in reset B using just one reset, where the conditional statement is in the reset value rather than the test value.
While they will work in this situation, it’s better to avoid using conditional statements with resets if possible. The situation above could be reframed to supply the extra battery conditions like this:
model: CleaningTheHouse
└─ component: Roomba
├─ variable: position [metre], initially 0
├─ variable: width [metre], constant 5
├─ variable: battery_level [charge], initially 100
│
├─ variable: battery_check [dimensionless], initially 1
│ └─ reset C: order = 1
│ ├─ "when battery_level equals 10"
│ └─ "then set battery_check to 0"
│
├─ variable: velocity [metre_per_second], initially 0.1
│ ├─ reset A: order = 1
│ │ ├─ "when position equals width"
│ │ └─ "then velocity to be negative product with battery_check"
│ └─ reset B: order = 2
│ ├─ "when position equals start"
│ └─ "then set to be positive product with battery_check"
│
└─ math:
├─ ode(position, time) = velocity
└─ ode(battery_level, time) = -abs(velocity)
Show CellML syntax
<model name="CleaningTheHouse">
<component name="Roomba">
<variable name="position" units="metre" />
<variable name="width" units="metre" />
<variable name="battery_level" units="charge" initial_value="100" />
<variable name="velocity" units="metre_per_second" initial_value="0.1" />
<variable name="battery_check" units="dimensionless" initial_value="0" />
<!-- Resets active at any position tell when the battery check means it should
be stopped at the next wall encounter. Note that this doesn't actually affect
the velocity of the Roomba until either reset A or B is active. -->
<reset variable="battery_check" test_variable="battery_level" order="1">
<test_value>
<cn cellml:units="charge">10</cn>
</test_value>
<reset_value>
<ci cellml:units="dimensionless">1</ci>
</reset_value>
</reset>
<!-- Reset A will set a negative velocity when the Roomba reaches
the opposite wall, provided the battery_check is not zero. -->
<reset variable="velocity" test_variable="position" order="1">
<test_value>
<ci>width</ci>
</test_value>
<reset_value>
<apply>
<times/>
<cn cellml:units="metre_per_second">-0.1</cn>
<ci>battery_check</ci>
</apply>
</reset_value>
</reset>
<!-- Reset B2 will set a positive velocity when the Roomba reaches
the starting wall, provided the battery_check is not zero. -->
<reset variable="velocity" test_variable="position" order="2">
<test_value>
<cn cellml:units="metre">0</cn>
</test_value>
<reset_value>
<apply>
<times/>
<cn cellml:units="metre_per_second">0.1</cn>
<ci>battery_check</ci>
</apply>
</reset_value>
</reset>
<math>
<!-- Setting the width of the room as a constant: -->
<apply>
<eq/>
<ci>width</ci>
<cn cellml:units="metre">5</cn>
</apply>
<!-- Simple ODE for position of the Roomba with time: -->
<apply>
<eq/>
<diff>
<ci>position</ci>
<bvar>time</bvar>
</diff>
<ci>velocity</ci>
</apply>
<!-- Simple ODE for charge of the Roomba with time: -->
<apply>
<eq/>
<diff>
<ci>battery_level</ci>
<bvar>time</bvar>
</diff>
<apply>
<times/>
<apply>
<abs/>
<ci>velocity</ci>
</apply>
<cn units:cellml="charge_second_per_metre">-1</cn>
</apply>
</apply>
</math>
</component>
<!-- Custom units needed: -->
<units name="metre_per_second">
<unit units="metre" />
<unit units="second" exponent="-1" />
</units>
<units name="charge"/>
<units name="charge_second_per_metre">
<unit units="charge" />
<unit units="metre_per_second" exponent="-1"/>
</units>
</model>
References¶
RFC 2119: Key words for use in RFCs to Indicate Requirement Levels https://www.ietf.org/rfc/rfc2119.txt
XML Information Set (Second Edition) https://www.w3.org/TR/2004/REC-xml-infoset-20040204/
Namespaces in XML 1.1 (Second Edition) https://www.w3.org/TR/xml-names11/
Unicode® 13.0.0 https://www.unicode.org/versions/Unicode13.0.0/
Extensible Markup Language (XML) 1.1 (Second Edition) https://www.w3.org/TR/xml11/
XML Linking Language (XLink) Version 1.1 https://www.w3.org/TR/xlink11/
Mathematical Markup Language (MathML) Version 2.0 (Second Edition) https://www.w3.org/TR/MathML2/
Examples¶
Using resets¶
Introduction¶
This document is not part of the CellML specification. It gives a suggested interpretation of resets, and involves adding some rules and restrictions on the mathematics described by a CellML document. It is perfectly valid for a CellML model to break these rules and/or go beyond these restrictions. In that case, the interpretation given here may not hold.
For the purposes of this document, we use the term “variable” to mean “the mathematical variable represented by a connected variable set” (see {number} {name}
)
A model’s variables can be divided into four sets:
The variable or variables of integration, \(t\). These are defined as all variables which appear inside the MathML
<bvar>
element inside a<diff>
.The state variables, \(x\). These are defined as all variables for which an initial value is defined.
The constant variables (or parameters), \(p\). These are all variables which are not in \((x, t)\), and whose values do not depend on any other variable.
The derived variables, \(z\). The variables that are not in \((x, t, p)\).
Some extra restrictions¶
None of the variables can have boolean values.
The variables in \(t\) must not be constrained by the model equations or resets: they must be free variables.
Any variable for which a derivative is used (i.e.: the variables in a
<diff>
but not in its<bvar>
) must define an initial value.The model must not be overdefined or underdefined.
The sets \(t, x, z\) and \(p\) must not overlap.
Note that, while some of the most biologically interesting variables are found be in \(z\), for the purposes of evaluating the system trajectory they are simply functions of \((x, t, p)\). For the sake of clarity we can omit them and could, for example, specify a function of the model’s state as \(f(x, t, p)\) instead of \(f(x, t, p, g(x, t, p))\).
Interpretation¶
CellML models define two functions:
\(f(x, t, p) \to fx\) calculates the system derivatives \(fx\) at any point \((x, t, p)\). Note that x contains variables for which an initial value, but no derivative, was defined. For these variables \(fx\) is zero.
\(g(x, t, p) \to (x^\prime, t, p)\) is a discontinuous mapping from one or more points \((x, t, p)\) to points \((x^\prime, t, p)\). Note that \(g\) can only change the values of \(x\). The values of variables in \(p\) are already fixed by model equations, while we posited above that \(t\) is not constrained by the model equations or resets.
The first function, \(f(x, t, p) \to fx\), is defined by the equations in the model. The second function, \(g(x, t, p) \to (x^\prime, t, p)\), is defined by the collection of reset rules in the model. Note that both parts are optional: a user can supply \(f\), \(g\), both, or neither.
When started at some initial point \((x_0, t_0, p_0)\), the derivatives in \(f\) describe the system’s trajectory through \((x, t, p)\)-space. Reset rules add the ability to specify some values \((x, t, p)\) for which the system should instantaneously jump. This is illustrated below, where a trajectory (black line) is interrupted at point \((x, t, p)\) by a discontinuous jump (dashed line) to \((x^\prime, t, p)\).

A discontinuous jump in parameter or variable value is made possible by resets.¶
Multiple reset rules can act together: \(g\) is a composite function¶
It is important to note that \(g\) is defined by all reset rules in the model (including those from imported parts).
An individual reset rule is triggered whenever the value of its test variable (some function of \((x, t, p)\)) equals its test value (another function of \((x, t, p)\)).
At that point, the value of its reset variable (the variable referenced in the variable
attribute) should be updated to the reset value.
If multiple reset rules apply to the same reset variable (which must be in either \(x\) or \(p\)) at the same point \((x, t, p)\), only the rule with the lowest order attribute will be triggered. The procedure below can be used to determine the jump occurring at a point \((x, t, p)\) :
For each reset rule, determine whether it is active by checking if its test variable’s value matches the test value at \((x, t, p)\).
If more than one reset rule is active for the same reset variable, only the rule with the lowest order is held to be active for that reset variable.
If only one reset rule is active for the same reset variable, select it.
For each active reset rule, calculate the specified change, using the values \((x, t, p)\) to perform any calculation of new values.
For each active reset rule, apply the calculated change.
Test whether the system is in a new point \((x^\prime, t, p) \neq (x, t, p)\):
If so, then let \((x, t, p) := (x^\prime, t, p)\) and repeat, starting from step 1.
If not, return the new \((x, t, p)\).
Note that:
Reset rule evaluation can consist of multiple cycles through steps 1-4.
For each cycle, all reset rules are tested before any changes are made.
For each cycle, because only one reset rule can hold per variable, changes to the system state are orthogonal (see Figure 5.2); this ensures that the order in which the rules are applied does not matter.
It is entirely possible for the user to specify infinite loops using reset rules, e.g.: by having the effects of one rule undoing the effects of a previous one.

Reset rules are applied individually to a variable, ensuring that the order in which they are applied does not affect the final system state; the changes are orthogonal.¶
Finding the points \((x, t, p)\)¶
Because it is highly unlikely for a simulated trajectory to include a point \((x, t, p)\) exactly, solvers must check if they have passed such a point: for example, by checking if the sign of (test_variable - test_value) has changed. If this occurs, it is up to the solver to decide whether to treat the current point as the discontinuity (inexact), or to backtrack and try to find the threshold crossing point exactly. A graphical example of a “lazy” implementation is given in Figure 5.3.

Resets may be triggered by a change in sign, indicating that the trajectory has been crossed. Implementations may use the “lazy” value at the point of detection, or backtracl to determine the point of crossing more exactly.¶
A particularly difficult case occurs if a reset rule is defined in such a way that (test_variable - test_value) can pass through a root without changing sign (for example, a reset when \(sin(t) == 1\) as in Figure 5.4).

It’s possible for resets to be undetectable when the reset occurs at a root, because the step can pass over the function line without changing sign.¶
Using this type of reset rule in a simulation may lead to unexpected results, so - like dividing by zero or using reset rules to create infinite loops - is probably best avoided.
Examples of reset use¶
Example: Duplicated test conditions¶
Description: Here we show a simple example involving two resets which are both triggered by the same test_variable
and test_value
condition: B == 3
.
Despite this, the resets alter different variables (they have different reset_variable
attributes) and can thus be evaluated during the same loop, without needing to refer to the order
attribute.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math: ode(B, t) = 1
│
├─ variable: A initially 1
│ └─ reset: rule 1
│ ├─ when B == 3
│ └─ then A = 2
│
└─ variable: B initially 1
└─ reset: rule 2
├─ when B == 3
└─ then B = 1
See CellML syntax
<variable name="A" units="dimensionless" initial_value="1" />
<variable name="B" units="dimensionless" initial_value="1" />
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="A" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">2</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="B" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
At t = 2
the following situation occurs:
t |
0 |
1 |
2 |
A |
1 |
1 |
1 |
B |
1 |
2 |
3 |
At this point, the integrator checks all reset rules, finding an active reset for both A and B. As a result, both values are updated:
t |
0 |
1 |
2 |
A |
1 |
1 |
1 → 2 |
B |
1 |
2 |
3 → 1 |
Changes have been made, so a second cycle of reset evaluations is started. No active reset rules are found so model dynamics continue.
t |
0 |
1 |
2 |
2 + dt |
3 |
A |
1 |
1 |
1 → 2 |
2 |
2 |
B |
1 |
2 |
3 → 1 |
1 + dt |
2 |
Example: Reset to same¶
Description: This example shows how reset evaluation halts if the model’s set of system values \((x, t, p)\) has stopped changing. The reset itself doesn’t actually do anything, but it does go through the process of checking the active resets, applying them, and deciding whether or not to continue the reset evaluation loop.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math: ode(A, t) = 1
└─ variable: A initially 1
└─ reset:
├─ when t == 1
└─ then A = 2
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<math>
<apply><eq/>
<diff>
<ci>A</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<reset variable="A" test_variable="t">
<test_value>
<cn units="cellml:dimensionless">1</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">2</cn>
</reset_value>
</reset>
t |
0.0 |
… |
0.8 |
0.9 |
1.0 |
A |
1 |
… |
1.8 |
1.9 |
2 |
At t = 1.0
the reset rule for A becomes active.
The update is calculated as A = 2
, and (finding no other values need to be calculated) the change is applied.
After applying the change, the new point \((x^\prime, t, p)\) equals the old point \((x, t, p)\) and so reset evaluation is halted, and model dynamics continue.
t |
0.0 |
… |
0.8 |
0.9 |
1.0 |
1.1 |
1.2 |
A |
1 |
… |
1.8 |
1.9 |
2 → 2 |
2.1 |
2.2 |
Example: Order of evaluation¶
Description: This example shows the behaviour when a reset value involves a variable.
Note that:
all elements are in the same component;
resets are shown attached to their
variable
attribute;the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math: ode(B, t) = 1
│
├─ variable: A initially 1
│ └─ reset: rule 1
│ ├─ when B == 3
│ └─ then A = B
│
└─ variable: B initially 1
└─ reset: rule 2
├─ when B == 3
└─ then B = 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<variable name="B" units="dimensionless" initial_value="1" />
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="A" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<ci>B</ci>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="A" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<ci>B</ci>
</reset_value>
</reset>
At t = 2
the following situation occurs:
t |
0 |
1 |
2 |
A |
1 |
1 |
1 |
B |
1 |
2 |
3 |
At this point \((x, t, p)\), the test conditions for both resets are true, so both are active. New values are first calculated, and then applied to yield a new point \((x^\prime, t, p)\):
t |
0 |
1 |
2 |
A |
1 |
1 |
1 → 3 |
B |
1 |
2 |
3 → 1 |
Note that both tests are performed using \((x, t, p)\), so the order of these tests doesn’t change the outcome. Secondly, because the changes are orthogonal (each reset affects a different node in the directed acyclic graph), we can apply them in any order and reach the same point \((x^\prime, t, p)\).
Because \((x^\prime,t, p) \neq (x, t, p)\) a second round of reset evaluation is started, but no active resets are found, the reset evaluation is halted and model dynamics continue.
t |
0 |
1 |
2 |
2 + dt |
3 |
A |
1 |
1 |
1 → 3 |
3 |
3 |
B |
1 |
2 |
3 → 1 |
1 + dt |
2 |
Example: Cascading¶
Description: Because resets change the value of variables, they can also trigger downstream reset activity as conditions which were not previously met become active.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math:
│ ├─ ode(A, t) = 1
│ └─ ode(B, t) = 1
│
├─ variable: A initially 1
│ └─ reset: rule 1
│ ├─ when A == 4
│ └─ then B = 5
│
└─ variable: B initially 2
└─ reset: rule 2
├─ when A == 5
└─ then B = 6
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<variable name="B" units="dimensionless" initial_value="2" />
<math>
<apply><eq/>
<diff>
<ci>A</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="A" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">4</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">5</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="B" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">5</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">6</cn>
</reset_value>
</reset>
At t = 2
the following situation occurs:
t |
0 |
1 |
2 |
A |
1 |
2 |
3 |
B |
2 |
3 |
4 |
At this point reset rule 1 is the only active reset. The change is applied:
t |
0 |
1 |
2 |
A |
1 |
2 |
3 → 5 |
B |
2 |
3 |
4 |
Because the new point differs from the last, a second cycle of reset rule checking is started. In this cycle, only reset rule 2 is active. Again, the change is applied:
t |
0 |
1 |
2 |
A |
1 |
2 |
3 → 5 |
B |
2 |
3 |
4 → 6 |
A third cycle is started, in which B is still active, but after applying the updates the new point is the same as at the end of cycle two, so reset evaluations halts and model dynamics continue.
t |
0 |
1 |
2 |
3 |
… |
A |
1 |
2 |
3 → 5 |
6 |
… |
B |
2 |
3 |
4 → 6 |
7 |
… |
Example: Using variables as reset values¶
Description: A simple example demonstrating the behaviour where one variable is reset to the value of another.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math:
│ └─ ode(B, t) = 1
│
├─ variable: A initially 1
│ └─ reset: rule 1
│ ├─ when B == 4
│ └─ then A = A + 1
│
└─ variable: B initially 3
└─ reset: rule 2
├─ when A == 2
└─ then B = A + B
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<variable name="B" units="dimensionless" initial_value="3" />
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="A" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">4</cn>
</test_value>
<!-- Variable A is given a value of A+1 when B equals 4. -->
<reset_value>
<apply><plus/>
<ci>A</ci>
<cn cellml:units="dimensionless">1</cn>
</apply>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="B" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">2</cn>
</test_value>
<!-- Variable B is given a value of A+B when A equals 2. -->
<reset_value>
<apply><plus/>
<ci>A</ci>
<ci>B</ci>
</apply>
</reset_value>
</reset>
At t = 1
the following situation occurs:
t |
0 |
1 |
A |
1 |
1 |
B |
3 |
4 |
At this point, reset rule 1 for A is active.
Its new value is calculated to be A → A + 1 = 1 + 1 = 2
.
t |
0 |
1 |
A |
1 |
1 → 2 |
B |
3 |
4 |
This is a new point, so reset evaluation enters a second cycle.
In this cycle, the resets for both A and B are active.
The new values are calculated to be A → A + 1 = 2 + 1 = 3
, and B → A + B = 2 + 4 = 6
.
The new values are applied:
t |
0 |
1 |
A |
1 |
1 → 2 → 3 |
B |
3 |
4 → 6 |
A new cycle of reset evaluation is applied, but finds no active resets, so model dynamics continue.
Example: Using variables as test values¶
Description: A simple example showing the behaviour when a reset test value is given by a variable.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component:
├─ math:
│ └─ ode(A, t) = 1
│
├─ variable: A initially 1
│
└─ variable: B initially 2
└─ reset:
├─ when B == A
└─ then B = B + 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<variable name="B" units="dimensionless" initial_value="2" />
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<reset variable="B" test_variable="B">
<test_value>
<ci>A</ci>
</test_value>
<!-- Variable B is given a value of B+1 when B equals A. -->
<reset_value>
<apply><plus/>
<ci>B</ci>
<cn cellml:units="dimensionless">1</cn>
</apply>
</reset_value>
</reset>
At t = 1
the following situation occurs:
t |
0 |
0.1 |
… |
1 |
A |
1 |
1.1 |
… |
2 |
B |
2 |
2 |
… |
2 |
The reset for B is now active, leading to the following update:
t |
0 |
0.1 |
… |
1 |
A |
1 |
1.1 |
… |
2 |
B |
2 |
2 |
… |
2 → 3 |
A change has been made, so a second cycle of evaluations is started. No resets are found to be active (B no longer equals A), and so model dynamics continue.
t |
0 |
0.1 |
… |
1 |
1.1 |
… |
2 |
2.1 |
A |
1 |
1.1 |
… |
2 |
2.1 |
… |
3 |
3.1 |
B |
2 |
2 |
… |
2 → 3 |
3 |
3 |
3 → 4 |
4 |
At t = 2
the reset rule is triggered a second time, in a similar fashion.
Example: Explicit reset ordering¶
Description: Resets which address the same variable can use the order
attribute to establish a priority for evaluation.
Note that “order” here refers to the sequence in which resets are tested, not the sequence in which they are applied.
The former determines which reset is selected in an evaluation cycle (only one reset per variable is applied); the latter does not affect the final system values (see Figure 5.2).
Note that:
all elements are in the same component; and
all variables have dimensionless units.
component:
├─ math:
│ ode(B, t) = 1
│
├─ variable: A initially 2
│ ├─ reset: rule 1
│ │ ├─ order = 1
│ │ ├─ when B == 4
│ │ └─ then A = 1
│ │
│ └─ reset: rule 2
│ ├─ order = 2
│ ├─ when B == 4
│ └─ then A = 3
│
└─ variable: B initially 3
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="2" />
<variable name="B" units="dimensionless" initial_value="3" />
<math>
<apply><eq/>
<diff>
<ci>B</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: order = 1 -->
<reset variable="A" test_variable="B" order="1">
<test_value>
<cn cellml:units="dimensionless">4</cn>
</test_value>
<reset_value>
<cn cellml:units="dimensionless">1</cn>
</reset_value>
</reset>
<!-- Reset rule 2: order = 2 -->
<reset variable="A" test_variable="B" order="2">
<test_value>
<cn cellml:units="dimensionless">4</cn>
</test_value>
<reset_value>
<cn cellml:units="dimensionless">3</cn>
</reset_value>
</reset>
At t = 1
the following situation occurs:
t |
0 |
1 |
A |
2 |
2 |
B |
3 |
4 |
There are now two different reset rules for A that could be active, so the one with the lower order (reset rule 1) is selected.
t |
0 |
1 |
A |
2 |
2 → 1 |
B |
3 |
4 |
The system has moved to a new point, so a second round of resets is run. Both resets are still active so again the reset with the lowest order is selected and applied, leading to the same result. After this second cycle the system has not changed, so reset evaluation is halted.
Implementation: Forward integration¶
Description: This example shows two possible strategies to handle resets. No particular method is prescribed (just as no method is prescribed for the solution of ODEs either).
Note that:
all elements are in the same component;
the order values of resets are not shown; and
the units of variables are not shown.
component: ForwardIntegration
├─ math:
│ └─ ode(A, t) = 1
│
└─ variable: A initially 1
└─ reset:
├─ when A == 3
└─ then A = 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<!-- Reset rule 1: -->
<reset variable="A" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
Near t = 1.9
, an integration step proceeds as normal: the derivatives \(f(x_1, t_1)\) are calculated, and used to estimate a step \((x_2, t_2)\).
The quantity A - 3
(test variable minus test value) is calculated and monitored for sign changes.
t |
1.9 |
Propose: 2.1 |
|
A |
2.9 |
Propose: 3.1 |
|
A - 3 |
-0.1 |
Propose: 0.1 |
After this step is proposed, the test variables are checked. Because the sign of A - 3
has changed, the integrator notices a discontinuity has occurred, and so the reset should be carried out as soon as possible.
To do this, the reset value is evaluated at \((x_1, t_1)\) - just like the derivatives were evaluated at \((x_1, t_1)\) earlier - and \(x_2\) is updated to reflect this change:
t |
1.9 |
Propose: 2.1 |
Accept: 2.1 |
A |
2.9 |
Propose: 3.1 |
Accept: 1 |
A - 3 |
-0.1 |
Propose: 0.1 |
Variable time-step methods can try and find the discontinuity, for example they could use threshold crossing algorithms to find a better proposed step:
t |
1.9 |
Propose: 2.1 |
Update: 2.0 |
Accept: 2.0 |
A |
2.9 |
Propose: 3.1 |
Update: 3 |
Accept: 1 |
A - 3 |
-0.1 |
Propose: 0.1 |
Update: 0 |
What could go wrong?¶
Misuse: Touching, not crossing¶
Description: Resets whose test_value
coincides with a turning point of the test_variable
risk missing detection of the reset point.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
the units of variables are not shown.
component: TouchingNotCrossing
├─ math: x = sin(t*pi/2)
├─ variable: x
└─ variable: y initially 0
├─ reset: rule 1
│ ├─ when x == 1
│ └─ then y = 1
└─ reset: rule 2
├─ when x == -1
└─ then y = 0
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<math>
<apply><eq/>
<ci>x</ci>
<apply><sin/>
<apply><times/>
<ci>t</ci>
<apply><divide/>
<pi/>
<cn cellml:units="dimensionless">2</cn>
</apply>
</apply>
</apply>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">1</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">-1</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">0</cn>
</reset_value>
</reset>
A simulation with this model might proceed as follows:
t |
0.0 |
0.1 |
… |
0.9 |
1.0 |
1.1 |
… |
2.9 |
3.0 |
3.3 |
… |
x |
0 |
0.156 |
… |
0.988 |
1 |
0.988 |
… |
-0.988 |
-1 |
0.988 |
… |
y |
0 |
0 |
… |
0 |
0 → 1 |
1 |
… |
1 |
1 → 0 |
0 |
… |
However, it is easy for implementations to “miss” this type of reset in a simulation.
For example, the following may occur in an implementation with adaptive step sizes that uses root finding to detect resets (i.e.: by searching for sign changes in x - 1
):
t |
0.0 |
0.4 |
… |
0.9 |
1.1 |
1.7 |
… |
x |
0 |
0.588 |
… |
0.988 |
0.988 |
0.454 |
… |
y |
0 |
0 |
… |
0 |
0 |
0 |
0 |
x - 1 |
-1 |
-0.412 |
… |
-0.12 |
-0.12 |
-0.546 |
… |
This behaviour is expected to be common in implementations. For example, the popular adaptive solver https://computing.llnl.gov/projects/sundials/cvodeCVODE has a root finding mechanism that can be used to implement reset rules, but its documentation explicitly states it is unlikely to find roots where the sign does not change. As a result, this type of reset rule is probably best avoided.
Suggestions¶
TODO ?
Misuse: Multiple truths¶
Description: The behaviour specified in resets must complement the mathematics of the model; it does not over-ride it. For this reason, models containing reset variables which are also present in maths statements are over-defined. This is shown in the example below.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component: MultipleTruths
├─ math:
│ ├─ x = t % 1000
│ └─ y = 0
│
├─ variable: x
│
└─ variable: y
└─ reset: rule 1
├─ when x == 100
└─ then y = 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" />
<math>
<!-- x = t % 1000 -->
<apply><eq/>
<ci>x</ci>
<apply><rem/>
<ci>t</ci>
<cn cellml:units="dimensionless">1000</cn>
</apply>
</apply>
<!-- y = 0 -->
<apply><eq/>
<ci>y</ci>
<cn cellml:units="dimensionless">0</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">100</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
t |
0.0 |
… |
99.9 |
100 |
x |
0 |
… |
99.9 |
100 |
y |
0 |
… |
0 |
0 → 1 ? |
At this point, the CellML model’s interpretation is not defined.
The reset causing y = 1
and the mathematics y = 0
cannot both be true.
Suggestions¶
There is no workaround that will give the behaviour of the model as it is: the situation is not possible. However, it’s probable that this occurred because you actually wanted a different behaviour:
Initial conditions: If the line in the maths block stating that \(y=0\) is intended to provide only an initial condition, you should remove it from the maths block. Statements here are held to be true for all time, so simple definitions such as \(a=1\) lock the value of \(a\) in stone: it cannot be changed by resets, by other mathematics, or by initial conditions. To initialise a variable whose value can be changed (including by a reset item) please use the
initial_value
attribute on the variable instead.Default conditions: If the use of a reset on variable y is intended to be a temporary situation, active only when the reset conditions are met, then the mathematics \(y=0\) should again be removed. Resets provide a one-way switch: in the case of the reset above this switch is from \(y=0→1\). To switch back the other way (making the condition temporary), simply provide a second reset, as shown below.
In any case, the using both maths and resets to set the value of a variable can lead to problems. Use one, or the other, but not both!
component: MultipleTruths ├─ math: │ └─ x = t % 1000 │ <------------- maths involving y is deleted │ ├─ variable: x └─ variable: y ├─ reset: rule 1 │ ├─ when x == 100 │ └─ then y = 1 │ └─ reset: rule 2 <-------- reset to switch back is provided ├─ when x == 101 └─ then y = 0
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" />
<math>
<!-- x = t % 1000 -->
<apply><eq/>
<ci>x</ci>
<apply><rem/>
<ci>t</ci>
<cn cellml:units="dimensionless">1000</cn>
</apply>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">100</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">101</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">0</cn>
</reset_value>
</reset>
Misuse: Indirect change of state variables¶
Description: Resets applied at \((x, t, p)\) can only change the variables in \(x\).
This includes state variables, and variables which have been initialised using the initial_value
attribute and whose value is not determined through any of the mathematical equations given.
This example shows the valid case of where the mathematical equation may - depending on the implementation - covertly change a state variable.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
the units of variables are not shown.
component: IndirectlyChangeStateVariables
├─ math:
│ ├─ ode(A, t) = 1
│ └─ B = A
│
├─ variable: A initially 1
│
└─ variable: B
└─ reset:
├─ when B == 2
└─ then B = 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1"/>
<variable name="B" units="dimensionless" />
<math>
<apply><eq/>
<diff>
<ci>A</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<reset variable="B" test_variable="B">
<test_value>
<cn units="cellml:dimensionless">1</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">2</cn>
</reset_value>
</reset>
This is similar to the previous case, but now the situation could perhaps be solvable:
Initially, both A and B are 1.
As the solution progresses, the solved value for A is given as the value for B because of the equality \(B=A\) in the maths block.
When
B == 2
, the reset is triggered and B is reset to 1.
Thus it’s unclear whether different implementations and solvers would show consistent behaviour, and this kind of model formulation is better avoided.
t |
0.0 |
… |
1 |
|
A |
1 |
… |
2 |
? |
B |
1 |
… |
2 |
1 → 2 |
(In addition, determining whether a situation like this does or does not have a solution has the potential to be difficult.)
Suggestions¶
Since the issue arises in the interpretation of the reset and mathematics into code, that is where the solution lies also.
In most implementations the equality \(=\) will be converted to an assignment (e.g.: B := A
) before the system is solved.
In turn, this means that the system is not over-defined, and solution is possible.
Allowing this type of situation would mean solvers need to recognise potential situations like this and add statements which decide which direction of the assignment should be followed:
if (some condition):
then: assign the value of A to B
else: assign the value of B to A
Misuse: Conditional reset value¶
Description: This example shows the valid, but inadvisable, situation of how conditional statements may be given to reset values, and gives an alternative arrangement with the same functionality. The desired behaviour is shown in Fig. 5.5.

Expected behaviour of a reset with a conditional reset value.¶
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component: ConditionalResetValue
├─ math:
│ └─ x = sin(t*pi)
│
├─ variable: x
│
└─ variable: y initially 0
└─ reset:
├─ when x == 0
└─ then if sin((t-0.1)*pi) < 0
├─ then y = 1
└─ else y = 0
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<math>
<apply><eq/>
<ci>x</ci>
<apply><sin/>
<apply><times/>
<ci>t</ci>
<pi/>
</apply>
</apply>
</apply>
</math>
<reset variable="y" test_variable="x">
<!-- The test value is constant: -->
<test_value>
<cn cellml:units="dimensionless">0</cn>
</test_value>
<!-- The reset value is decided based on:
if sin((t-0.1)*pi) < 0:
then reset_value = 1
else reset_value = 0
-->
<reset_value>
<piecewise>
<piece>
<!-- Conditional statement to decide the reset value. -->
<apply><lt/>
<apply><sin/>
<apply><times/>
<apply><minus/>
<ci>t</ci>
<cn cellml:units="dimensionless">0.1</cn>
</apply>
<pi/>
</apply>
</apply>
<cn cellml:units="dimensionless">0</cn>
</apply>
<!-- If the condition is met, the reset value is 1. -->
<cn cellml:units="dimensionless">1</cn>
</piece>
<otherwise>
<!-- If the condition above is not met, the reset value is 0. -->
<cn cellml:units="dimensionless">0</cn>
</otherwise>
</piecewise>
</reset_value>
</reset>
It is valid, though probably not advisable, to use conditional statements (the MathML piecewise
, piece
and otherwise
items) when specifying a reset value.
Two alternative arranements which give the same behaviour are shown below.
Suggestions¶
In the first, we create a dummy variable r and apply the conditional statement to its value external to the reset. When the reset is active, the value of r is retrieved and used as normal.
component: AvoidingConditionalResetValue1
├─ math:
│ ├─ x = sin(t*pi)
│ └─ r = if sin((t-0.1)*pi) < 0 then 1 else 0
│
├─ variable: x
├─ variable: r
└─ variable: y initially 0
└─ reset:
├─ when x == 0
└─ then y = r
Show CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<!-- Include an additional variable and use its value to pass to the reset.-->
<variable name="r" units="dimensionless" />
<math>
<apply>
<eq/>
<ci>x</ci>
<apply>
<sin/>
<apply>
<times/>
<ci>t</ci>
<pi/>
</apply>
</apply>
</apply>
<!-- Include the evaluation of the additional variable in the MathML block.
The value of r will change each iteration, but will only be passed on to
the y variable when the reset conditions are met. -->
<apply>
<eq/>
<ci>r</ci>
<piecewise>
<piece>
<!-- Conditional statement to decide the potential reset value. -->
<apply>
<lt/>
<apply>
<sin/>
<apply>
<times/>
<apply>
<minus/>
<ci>t</ci>
<cn cellml:units="dimensionless">0.1</cn>
</apply>
<pi/>
</apply>
</apply>
<cn cellml:units="dimensionless">0</cn>
</apply>
<!-- If the condition is met, then r is 1. -->
<cn cellml:units="dimensionless">1</cn>
</piece>
<otherwise>
<!-- If the condition above is not met, then r is 0. -->
<cn cellml:units="dimensionless">0</cn>
</otherwise>
</piecewise>
</apply>
</math>
<reset variable="y" test_variable="x">
<!-- The test value is constant: -->
<test_value>
<cn cellml:units="dimensionless">0</cn>
</test_value>
<!-- The reset value now uses a pre-computed variable, r: -->
<reset_value>
<ci>r</ci>
</reset_value>
</reset>
The second method also uses additional resets instead of conditional statements to decide the reset value.
component: AvoidingConditionalResetValue2
├─ math:
│ ├─ x = sin(t*pi)
│ └─ r_test = (sin((t-0.1)*pi))/abs(sin((t-0.1)*pi)
│
├─ variable: x
├─ variable: r_test
├─ variable: r
│ ├─ reset:
│ │ ├─ when r_test == -1
│ │ └─ then r = 1
│ └─ reset:
│ ├─ when r_test == 1
│ └─ then r = 0
│
└─ variable: y initially 0
└─ reset:
├─ when x == 0
└─ then y = r
Show CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<variable name="r" units="dimensionless" />
<!-- Include a sign variable to reset the value of r to pass to the reset for y.-->
<variable name="r_sign" units="dimensionless" />
<math>
<apply>
<eq/>
<ci>x</ci>
<apply>
<sin/>
<apply>
<times/>
<ci>t</ci>
<pi/>
</apply>
</apply>
</apply>
<!-- Include the evaluation of the additional variable in the MathML block.
The value of r will change each iteration, but will only be passed on to
the y variable when the reset conditions are met. -->
<apply>
<eq/>
<ci>r_sign</ci>
<apply>
<divide/>
<!-- Potential for divide by zero! Danger! -->
<apply>
<abs/>
<apply>
<sin/>
<apply>
<times/>
<apply>
<minus/>
<ci>t</ci>
<cn cellml:units="dimensionless">0.1</cn>
</apply>
<pi/>
</apply>
</apply>
</apply>
<apply>
<sin/>
<apply>
<times/>
<apply>
<minus/>
<ci>t</ci>
<cn cellml:units="dimensionless">0.1</cn>
</apply>
<pi/>
</apply>
</apply>
</apply>
</apply>
</math>
<!-- Two new resets which determine the value of r to be passed (when applicable) to the y variable: -->
<reset variable="r" test_variable="r_sign" order="2">
<test_value>
<cn cellml:units="dimensionless">1</cn>
</test_value>
<reset_value>
<cn cellml:units="dimensionless">0</cn>
</reset_value>
</reset>
<reset variable="r" test_variable="r_sign" order="1">
<test_value>
<cn cellml:units="dimensionless">-1</cn>
</test_value>
<reset_value>
<cn cellml:units="dimensionless">1</cn>
</reset_value>
</reset>
<reset variable="y" test_variable="x">
<test_value>
<cn cellml:units="dimensionless">0</cn>
</test_value>
<!-- The reset value now uses the pre-computed variable, r. -->
<reset_value>
<ci>r</ci>
</reset_value>
</reset>
Misuse: Conditional test value¶
Description: Similar to the conditional reset value situation, the use of conditional statements in the test value is valid CellML, but should be avoided.
The use of conditional statements in the test value is valid CellML, but should be avoided if those conditional statements introduce discontinuities.
The reset
elements are intended to alert the solver to the presence of a discontinuity in a CellML model, and to provide information on how that discontinuity should be interpreted (especially in the presence of other, possibly conflicting conditions).
Hiding a discontinuity within the reset defeats its purpose, as well as being a very difficult case for solvers to handle reliably (like \(x = 3e99999 + y - 2e99999 - 1e99999\) is mathematically valid but unlikely to be computed well).
Consider the example below.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component: ConditionalTestValue
├─ variable: t
├─ variable: x initially 0
└─ variable: y initially 0
└─ reset:
├─ when y == (if t == 1 then 1 else 0)
└─ then y = 1
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" initial_value="0" />
<variable name="y" units="dimensionless" initial_value="0" />
<reset variable="y" test_variable="x">
<!-- The test value is conditional: -->
<test_value>
<piecewise>
<piece>
<!-- Conditional statement to decide the test value. -->
<apply><eq/>
<ci>t</ci>
<cn cellml:units="dimensionless">1</cn>
</apply>
<!-- If the condition is met, the test value is 0. -->
<cn cellml:units="dimensionless">0</cn>
</piece>
<otherwise>
<!-- If the condition above is not met, the test value is 10. -->
<cn cellml:units="dimensionless">10</cn>
</otherwise>
</piecewise>
</test_value>
<!-- The reset value is constant: -->
<reset_value>
<cn cellml:units="dimensionless">1</cn>
</reset_value>
</reset>
Suggestions¶
Simply by moving the conditional statement from the test value and into a variable in the maths block gets around the problem; the discontinuity is visible to the solver. Since the resets will be applied after the mathematics is evaluated, the interpretation of the discontinuity is clear and straightforward.
component: AvoidConditionalTestValue
├─ variable: t
├─ variable: x initially 0
├─ variable: y initially 0
│ └─ reset:
│ ├─ when y == r
│ └─ then y = 1
├─ variable: r
│
└─ math:
└─ r = (if t == 1 then 1 else 0)
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" initial_value="0" />
<variable name="y" units="dimensionless" initial_value="0" />
<!-- Adding a dummy variable to transfer the conditional statement to: -->
<variable name="r" units="dimensionless" />
<reset variable="y" test_variable="x">
<!-- The test value is no longer conditional. -->
<test_value>
<ci>r</ci>
</test_value>
<reset_value>
<cn cellml:units="dimensionless">1</cn>
</reset_value>
</reset>
<!-- Moving the conditional statement into the MathML block, setting
the value to the new dummy variable: -->
<math>
<apply>
<eq/>
<ci>r</ci>
<piecewise>
<piece>
<!-- Conditional statement to decide the test value. -->
<apply>
<eq/>
<ci>t</ci>
<cn cellml:units="dimensionless">1</cn>
</apply>
<!-- If the condition is met, the test value is 0. -->
<cn cellml:units="dimensionless">0</cn>
</piece>
<otherwise>
<!-- If the condition above is not met, the test value is 10. -->
<cn cellml:units="dimensionless">10</cn>
</otherwise>
</piecewise>
</apply>
</math>
Misuse: Infinite loop¶
Description: It’s possible to write valid CellML syntax that produces an invalid or meaningless outcome. One such example is the use of resets to create infinite evaluation loops, where resets change a variable’s value back and forth forever.
Note that:
all elements are in the same component;
the order values of resets are not shown; and
all variables have dimensionless units.
component: InfiniteLoop
├─ math:
│ └─ ode(A, t) = 1
│
└─ variable: A initially 1
├─ reset: rule 1
│ ├─ when A == 2
│ └─ then A = 3
│
└─ reset: rule 2
├─ when A == 3
└─ then A = 2
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="A" units="dimensionless" initial_value="1" />
<math>
<apply><eq/>
<diff>
<ci>A</ci>
<bvar>t</bvar>
</diff>
<cn cellml:units="dimensionless">1</cn>
</apply>
</math>
<!-- Reset rule 1: -->
<reset variable="A" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">2</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">3</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="A" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">3</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">2</cn>
</reset_value>
</reset>
At t = 1
the following situation occurs:
t |
0 |
1 |
A |
1 |
2 |
There is exactly one reset rule active for A, and its change gets applied:
t |
0 |
1 |
A |
1 |
2 → 3 |
Because the new point differs from the last, a second cycle of reset rule checking is started. Again, a reset rule is active, and gets applied:
t |
0 |
1 |
A |
1 |
2 → 3 → 2 … |
Now we’re back in the original situation where the first reset rule is active, and so reset rule evaluation continues ad infinitum.
Good software might, at this point, detect that (1) the new point equals the original point before reset evaluation, but (2) reset rule evaluation has not yet terminated.
This points to an infinite loop, and so perhaps a runtime error.
But note that, as with e.g. x = 1 / 0
there is nothing in CellML to prevent users writing these things down.
Modelling examples¶
Usecase: Cell growth and division¶
Description: In this example, A represents the size of a cell, which grows until it reaches a threshold size and then divides.
component: CellGrowthAndDivision
├─ math: ode(A, t) = 1
└─ variable: A, initially 1
└─ reset:
├─ when A == 2
└─ then A = 1
See CellML syntax
<variable name="A" initial_value="1" units="dimensionless" />
<reset variable="A" test_variable="A">
<test_value>
<cn units="cellml:dimensionless">2</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
t |
0.0 |
… |
0.8 |
0.9 |
1.0 |
1.1 |
1.2 |
A |
1.1 |
… |
1.8 |
1.9 |
2 → 1 |
1.1 |
1.2 |
Processing steps
Cycle 1:
At
t = 1.0
we detect thatA == 2
, so the reset rule becomes active.The reset value is calculated to be 1.
The reset value is applied.
The system is now in a new state \((x^\prime, t, p) \neq (x, t, p)\) (note that \(A\) is included in \(x\)), we restart at step 1.
Cycle 2:
No reset rules are active, so evaluation halts.
Usecase: Stimulus current with offset¶
Description: Many electrophysiology models contain statements such as: I_stim = stim_amplitude if (time % 1000 < 2) else 0
.
These statements encode discontinuities directly into the mathematics (at t=0, t=1000, t=2000,… and at t=2, t=1002, t=2002, …), and so can be replaced by reset statements.
component: StimulusCurrentWithOffset
├─ math:
│ └─ x = t % 1000
│
├─ variable: x
│
└─ variable: y, initially 0
├─ reset: rule 1
│ ├─ when x == 100
│ └─ then y = 1
│
└─ reset: rule 2
├─ when x == 101
└─ then y = 0
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<!-- Reset rule 1: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">100</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">101</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">0</cn>
</reset_value>
</reset>
t |
0.0 |
… |
99.9 |
100 |
… |
100.9 |
101 |
x |
0 |
… |
99.9 |
100 |
… |
100.9 |
101 |
y |
0 |
… |
0 |
0 → 1 |
… |
1 |
1 → 0 |
Processing steps
Cycle
At
t = 100
we detect thatx == 100
, so rule 1 becomes active.The reset value for rule 1 is calculated to be 1.
The reset value for rule 1 is applied to
y
.The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\) (note that \(y\) is included in \(x\)), we restart at step 1.
Cycle
Since it is still true that
x == 100
, rule 1 is still active.The reset value is calculated,
And applied.
The state hasn’t changed: \((x^\prime, t, p) = (x, t, p)\), so reset rule 1 processing halts.
Cycle
At
t = 101
we detect thatx == 101
, so rule 2 becomes active.The reset value for rule 2 is calculated to be 0.
The reset value for rule 2 is applied to
y
.The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), so restart.
Cycle
Since it is still true that
x == 101
, rule 2 is still active.The reset value is calculated,
And applied.
The state hasn’t changed: \((x^\prime, t, p) = (x, t, p)\), so reset rule 2 processing halts.
Usecase: Reset at initial point¶
Description: This example shows that reset evaluation can happen throughout the simulation, including at the very beginning.
Note that:
all elements are in the same component;
the order values of resets are not shown;
all variables have
dimensionless
units;the initial conditions hold when
t = 0
.
component:
├─ math:
│ └─ x = t % 1000
│
├─ variable: x
│
└─ variable: y, initially 0
├─ reset: rule 1
│ ├─ when x == 0
│ └─ then y = 1
│
└─ reset: rule 2
├─ when x == 1
└─ then y = 0
See CellML syntax
<variable name="t" units="dimensionless" />
<variable name="x" units="dimensionless" />
<variable name="y" units="dimensionless" initial_value="0" />
<!-- Reset rule 1: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">0</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">1</cn>
</reset_value>
</reset>
<!-- Reset rule 2: -->
<reset variable="y" test_variable="x">
<test_value>
<cn units="cellml:dimensionless">1</cn>
</test_value>
<reset_value>
<cn units="cellml:dimensionless">0</cn>
</reset_value>
</reset>
Processing steps
t |
0.0 |
0.1 |
… |
x |
0 |
0.1 |
… |
y |
0 → 1 |
1 |
… |
Cycle 1
At
t = 0
we detect thatx == 0
, so rule 1 becomes active.The reset value for rule 1 is calculated to be 1.
The reset value for rule 1 is applied to
y
.The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), we restart at step 1.
Cycle 2
Since it is still true that
x == 0
, rule 1 is still active.The reset value for rule 1 is (again) calculated to be 1.
The reset value for rule 1 is (again) applied to
y
.The state hasn’t changed: \((x^\prime, t, p) == (x, t, p)\), so reset rule 1 processing halts.
Cycle 3
No other resets are found to be active, so the reset evaluation cycles finish and model dynamics continue.
t |
0.0 |
0.1 |
… |
0.9 |
1.0 |
1.1 |
… |
x |
0 |
0.1 |
… |
0.9 |
1.0 |
1.1 |
… |
y |
0 → 1 |
1 |
… |
1 |
1 → 0 |
0 |
… |
Cycle 4
At
t = 1
we detect thatx == 1
, so rule 2 becomes active.The reset value for rule 2 is calculated to be 0.
The reset value for rule 2 is applied to
y
.The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), so restart.
Cycle 5
Since it is still true that
x == 1
, rule 2 is still active.The reset value for rule 2 is calculated (still) to be 0.
And reset value for rule 2 is applied to
y
.The state hasn’t changed: \((x^\prime, t, p) == (x, t, p)\), so reset rule 2 processing halts.
Cycle 6
No other resets are found to be active, so the reset evaluation cycles finish and model dynamics continue.
Using imports¶
Using units¶
Best practice¶
This document is the informative version of the CellML 2.0 Specification, which combines the normative specification with examples and less formal explanations of CellML syntax and interpretation. Readers may expand the “See more” blocks throughout this document to access each section of the informative version and see the relevant examples and links.
The official normative specification document is to download from: https://www.cellml.org/specifications/cellml_2.0/cellml_2_0_1_normative_specification.pdf
Authors:
Michael Clerx, Michael T. Cooling, Jonathan Cooper, Alan Garny, Keri Moyle, David P. Nickerson, Poul Nielsen, and Hugh Sorby.
Contributors:
Koray Atalag, David Brooks, Edmund J. Crampin, Jesús Carro Fernández, Peter J. Hunter, Gary R. Mirams, and Maxwell L. Neal.
The authors also wish to acknowledge the significant contribution of the (discontinued) CellML 1.2 draft specification, much of the text of which was incorporated into this specification, although the semantics have changed considerably. The CellML 1.2 draft specification was itself the result of a collaborative effort by a number of researchers during 2008-2011:
Andrew K. Miller (who wrote the text reused here), Randall Britten, Jonathan Cooper, Alan Garny, Peter J. Hunter, Justin Marsh, Poul Nielsen, David P. Nickerson, and Hugh Sorby.
Contact: editors@cellml.org