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:

abcdefghijklmnopqrstuvwxyz (symbols between U+0061 and U+007A) ABCDEFGHIJKLMNOPQRSTUVWXYZ (symbols between U+0041 and U+005A)

These characters are referred to in CellML as the “Basic Latin alphabetical characters”.

The “digits” are the Unicode characters:

0123456789 (symbols between U+0030 and U+0039)

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

  1. Every CellML infoset SHALL be represented in an XML information set which conforms with the well-formedness requirements of XML 1.1 [5].

  2. 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

  1. 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):

    1. A document information item;

    2. An element information item;

    3. An attribute information item;

    4. A processing instruction information item;

    5. An unexpanded entity reference information item;

    6. A document type declaration information item;

    7. An unparsed entity information item; or

    8. A notational information item.

  2. 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.

  3. 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 and food_ideas have element contents, because they have child elements inside them,

  • category is an attribute of the recipe element, and name and units are attributes of the ingredient element, and

  • the 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

  1. 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):

    1. A comment information item;

    2. A namespace information item; or

    3. A character information item.

  2. 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>
  1. 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:

    1. Adding, removing, and/or modifying comment information items.

    2. 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.

    3. 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

  1. Element information items in a CellML infoset MUST belong to one of the following namespaces, unless explicitly indicated otherwise:

    1. The CellML namespace; or

    2. The MathML namespace.

  2. Attribute information items in a CellML element MUST NOT be prefixed with a namespace, unless explicitly indicated otherwise.

XML ID Attributes

  1. Any element information item in the CellML namespace MAY contain an attribute with local name id.

    1. 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 and variable), so this remains valid.

  • There is repetition of the id attribute “p” in the CarbohydrateIdeas.cellml document, between the variable named “Peanutbutter” and the component named “Porridge”. This is not valid.

Data representation formats in CellML

The following data representation formats are defined for use in this specification:

  1. A CellML identifier:

    1. 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.

    1. 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.

  1. An integer string:

    1. SHALL be a base 10 representation of an integer.

    1. MAY begin with a single Basic Latin plus character U+002B or a single Basic Latin hyphen-minus character U+002D as the sign indicator.

    1. 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, +.

  1. A basic real number string:

    1. SHALL be a base 10 representation of a real number.

    1. MAY begin with a single Basic Latin plus character U+002B or a single Basic Latin hyphen-minus character U+002D as the sign indicator.

    1. MAY contain a single decimal point separator, which SHALL be the Basic Latin full stop character U+002E.

    1. 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).

  1. A real number string:

    1. 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.

    1. The representation of the number SHALL be the representation of the significand, optionally followed by a representation of the exponent.

    1. The significand SHALL be represented as a basic real number string.

    1. 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.

    1. 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.

  1. Every model element MUST contain a name attribute.

    1. 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).

  1. A model element MAY contain one or more additional specific element children, each of which MUST be of one of the following types:

    1. A component element;

    2. A connection element;

    3. An encapsulation element;

    4. An import element; or

    5. A 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>
  1. A model element MUST NOT contain more than one encapsulation 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.

  1. Every import element MUST contain an attribute in the namespace http://www.w3.org/1999/xlink, with a local name equal to href.

    1. The value of this attribute SHALL be a valid locator href, as defined in Section 5.4 of the XLink specification [6].

    2. The href attribute SHALL be treated according to the XLink specification [6], by applying the rules for simple-type elements.

    3. 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 the href 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>
  1. Every import element MAY contain one or more specific element children, each of which MUST be of one of the following types:

    1. An import component element; or

    2. An 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.

  1. 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.

  1. Every import units element MUST contain a name attribute.

    1. The value of the name attribute MUST be a CellML identifier.

    2. The value of the name attribute MUST NOT be identical to the value of the name attribute of any other units or import units element in the CellML infoset.

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 called smallPotOfPaint in the example below).

  • A file to import from, specified using the xlink:href attribute of the parent import block. This is discussed in more detail in 2.2 The import element. In the example below this is the paint_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 the units_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>
  1. Every import units element MUST contain a units_ref attribute.

    1. The value of the units_ref attribute MUST be a CellML identifier.

    2. The value of the units_ref attribute MUST be identical to the value of the name attribute on a units or import 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.

  1. Every import component element MUST contain a name attribute.

    1. The value of the name attribute MUST be a CellML identifier.

    2. The value of the name attribute MUST NOT be identical to the value of the name attribute of any other component or import component element in the CellML infoset.

  1. Every import component element MUST contain a component_ref attribute.

    1. The value of the component_ref attribute MUST be a CellML identifier.

    2. The value of the component_ref attribute MUST be identical to the value of the name attribute on a component or import 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 called pi_calculator in the example below),

  • A file to import from, specified using the xlink:href attribute of the parent import block. This is discussed in more detail in 2.2 The import element. In the example below this is the pi_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 the component_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:

  1. 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.

  2. 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>
  1. 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 given href 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.

  1. Every units element MUST contain a name attribute.

    1. The value of the name attribute MUST be a CellML identifier.

    2. The value of the name attribute MUST NOT be identical to the value of the name attribute of any other units element or import units element in the CellML infoset.

  1. 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).

  1. A units element MAY contain one or more unit 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.

  1. Every unit element MUST contain a units attribute.

    1. The value of the units attribute MUST be a valid units reference, as defined in 3.2 Units references.

    1. The units element inclusion digraph SHALL contain an arc from units element A to units element B if and only if units element A contains a unit element with a units attribute value that is identical to the name attribute value of units element B.

    1. 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>
  1. A unit element MAY contain any of the following attributes:

    1. The prefix attribute.

      1. If present, the value of the attribute MUST meet the constraints specified in 3.3 Interpretation of units elements.

    1. The multiplier attribute.

      1. If present, the value of the attribute MUST be a real number string.

    1. The exponent attribute.

      1. 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.

  1. Every component element MUST contain a name attribute.

    1. The value of the name attribute MUST be a CellML identifier.

    2. The value of the name attribute MUST NOT be identical to the value of the name attribute on any other component element or import 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>
  1. A component element MAY contain one or more specific element children, each of which MUST be of one of the following types:

    1. A math element;

    2. A reset element; or

    3. A 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.

  1. Every variable element MUST have exactly one of each of the following attributes:

    1. The name attribute.

      1. The value of the name attribute MUST be a CellML identifier.

      2. The value of the name attribute MUST NOT be identical to the value of the name attribute on any sibling variable element.

    1. The units attribute.

      1. The value of the units attribute MUST be a valid units reference, as defined in 3.2 Units references.

  2. Every variable element MAY contain one or more of the following attributes:

    1. The interface attribute.

      1. If the attribute is present, it MUST have value of public, private, public_and_private, or none.

    1. The initial_value attribute.

      1. 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 the reset 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 this reset 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 the reset 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 this reset 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 each reset 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.

  1. Every reset element MUST have exactly one of each of the following attributes:

    1. The variable attribute.

      1. The value of the variable attribute MUST be a valid variable reference, as defined in 3.5 Variable references.

    1. The test_variable attribute.

      1. The value of the test_variable attribute MUST be a valid variable reference, as defined in 3.5 Variable references.

    2. The order attribute.

      1. The value of the order attribute MUST be an integer string.

      2. The value of the order attribute MUST be unique for all reset elements with variable 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>
  1. The order attribute.

    1. The value of the order attribute MUST be an integer string.

    2. The value of the order attribute MUST be unique for all reset elements with variable 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).

  1. A reset element MUST contain exactly two element children, which MUST be one of each of the following types:

    1. A reset_value element; and

    1. 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.

  1. A test_value element MUST contain exactly one math 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.

  1. A reset_value element MUST contain exactly one math 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.

  1. 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.

  1. 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>
  1. 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>
  1. A MathML cn element MUST have an attribute in the CellML namespace, with a local name equal to units.

    1. The value of the units attribute MUST be a valid units reference, as defined in 3.2 Units references.

  1. A MathML cn element MUST be base 10.

    1. 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.

Supported MathML elements

Element Category

Element List

Simple Operands

ci, cn, sep

Basic Structural

apply, piecewise, piece, otherwise

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

diff

Qualifier Elements

bvar, logbase, degree

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.

  1. An encapsulation element MAY contain one or more component_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.

  1. Every component_ref element MUST contain a component attribute.

    1. The value of the component attribute MUST be a valid component reference, as defined in 3.4 Component references.

    2. The value of the component attribute MUST NOT be identical to the value of the component attribute on any other component_ref element in the CellML infoset.

  1. Every component_ref element MAY in turn contain one or more component_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.

  1. Each connection element MUST contain a component_1 attribute.

    1. The value of the component_1 attribute MUST be a valid component reference, as defined in 3.4 Component references.

  1. Each connection element MUST contain a component_2 attribute.

    1. 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>
  1. The value of the component_1 attribute MUST NOT be identical to the value of the component_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>
  1. A CellML infoset MUST NOT contain more than one connection element with a given pair of components referenced by the component_1 and component_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>
  1. A connection element MAY contain one or more map_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.

  1. Each map_variables element MUST contain a variable_1 attribute.

    1. The value of the variable_1 attribute MUST be a valid variable reference, as defined in 3.5 Variable references.

  1. Each map_variables element MUST contain a variable_2 attribute.

    1. 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>
  1. A connection element MUST NOT contain more than one map_variables element with a given variable_1 attribute value and variable_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

  1. Each import units or import 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 parent import element’s href attribute.

  2. A units reference occurring within an imported element, SHALL be resolved with respect to the imported infoset.

  3. When determining the equivalent variable set of a variable in an imported component:

    1. Connections defined in the importing infoset SHALL be handled as described in 3.10 Interpretation of map_variables elements.

    2. Connections defined in the imported infoset SHALL be handled as follows:

      1. Connections to components in the encapsulated set of the imported component SHALL be maintained, and this rule SHALL be applied recursively; and

      2. 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.

  1. A units reference SHALL be a CellML identifier.

  2. The units identified by a units reference SHALL be determined as follows:

    1. 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.

    2. If the units reference is identical to the value of the name attribute of a units element in the same infoset, then it SHALL refer to the units specified by that element.

    3. If the units reference is identical to the value of the name attribute of an import units element in the same infoset, then it SHALL refer to units from the infoset defined by the import units element (see 3.1 Interpretation of import elements).

      1. The units specified SHALL then be determined by treating the value of the units_ref attribute on the import units element as a units reference within the imported infoset.

      2. If necessary, this rule SHALL be applied recursively.

  3. 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.

Built-in units
Name

Unit reduction tuple
multiplier⋅(base, exponent)

ampere

-

becquerel

(second, -1)

candela

-

coulomb

(second, 1), (ampere, 1)

dimensionless

-

farad

(kilogram, -1), (metre, -2), (second, 4), (ampere, 2)

gram

0.001⋅(kilogram, 1)

gray

(metre, 2), (second, -2)

henry

(kilogram, 1), (metre, 2), (second, -2), (ampere, -2)

hertz

(second, -1)

joule

(kilogram, 1), (metre, 2), (second, -2)

katal

(second, -1), (mole, 1)

kelvin

-

kilogram

-

litre

0.001⋅(metre, 3)

lumen

(candela, 1)

lux

(metre, -2), (candela, 1)

metre

-

mole

-

newton

(kilogram, 1), (metre, 1), (second, -2)

ohm

(kilogram, 1), (metre, 2), (second, -3), (ampere, -2)

pascal

(kilogram, 1), (metre, -1), (second, -2)

radian

(dimensionless, 1)

second

-

siemens

(kilogram, -1), (metre, -2), (second, 3), (ampere, 2)

sievert

(metre, 2), (second, -2)

steradian

(dimensionless, 1)

tesla

(kilogram, 1), (second, -2), (ampere, -1)

volt

(kilogram, 1), (metre, 2), (second, -3), (ampere, -1)

watt

(kilogram, 1), (metre, 2), (second, -3)

weber

(kilogram, 1), (metre, 2), (second, -2), (ampere, -1)

Interpretation of units elements

  1. The units element SHALL be interpreted as the product of its unit element children, according to the following rules:

    1. The prefix term is a conceptual property of unit elements.

      1. If the unit element does not have a prefix attribute, then the prefix term SHALL have value 0.

      2. 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.

      3. 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.

    2. The exponent term is a conceptual property of unit elements.

      1. If a unit element has no exponent attribute, then the exponent term SHALL have value 1.0.

      2. If a unit element has an exponent 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.

    3. The multiplier term is a conceptual property of unit elements.

      1. If a unit element has no multiplier attribute, then the multiplier term SHALL have value 1.0.

      2. If a unit element has a multiplier 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.

    4. The relationship between the product, \(P\), of numerical values given in each and every child unit element’s units attribute, to a numerical value, \(x\), with units given by the encompassing units 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).

  1. For the purposes of this specification, the “irreducible units” of a model SHALL consist of:

    1. 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 no unit child elements).

    2. 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.

  1. 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:

    1. If the units element has no unit child elements, then the set of tuples SHALL have a single member, which SHALL consist of the name of the units element and the exponent 1.0.

    2. If the units element has one or more unit child elements, then the set of tuples SHALL consist of the entire collection of tuples given by all unit child elements.

      Tuples for each unit child element SHALL be determined as follows:

      1. 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.

      1. 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.

      1. 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 the units element so referenced.

      2. 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.

    3. 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.

    4. 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`: joules 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 to apple, and

  • the 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 the cider_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>
Prefix values

Name

Value

yotta

24

zetta

21

exa

18

peta

15

tera

12

giga

9

mega

6

kilo

3

hecto

2

deca

1

deci

−1

centi

−2

milli

−3

micro

−6

nano

−9

pico

−12

femto

−15

atto

−18

zepto

−21

yocto

−24

Component references

A “component reference” is an attribute value that specifies a CellML component.

  1. A component reference SHALL be a CellML identifier.

  2. The component identified by a component reference SHALL be determined as follows:

    1. If the component reference is identical to the value of the name attribute of a component element in the same infoset, then it SHALL refer to the component specified by that element.

    2. If the component reference is identical to the value of the name attribute of an import component element in the same infoset, then it SHALL refer to a component from the infoset defined by the import component element (see 3.1 Interpretation of import elements).

      1. The component specified SHALL then be determined by treating the value of the component_ref attribute on the import component element as a component reference within the imported infoset.

      2. If necessary, this rule SHALL be applied recursively.

  3. 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.

  1. A variable reference SHALL be a CellML identifier.

  2. The variable identified by a variable reference SHALL be determined as follows:

    1. If present in a descendant of a component element, then it SHALL refer to the variable of the same name within that component.

    2. If present in the variable_1 attribute of a map_variables element, then it SHALL refer to the variable of the same name in the component identified by the component_1 attribute in the same map_variables element.

    3. If present in the variable_2 attribute of a map_variables element, then it SHALL refer to the variable of the same name in the component identified by the component_2 attribute in the same map_variables element.

  3. 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

  1. The conditions under which initial values hold are (by design) not defined in a CellML model.

  2. The initial_value attribute of a variable element MUST either be a real number string, or a variable reference.

  3. 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.

  4. 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 the initial_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 the math block, rather than via the initial_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 a math 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

  1. 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

  1. The following component elements SHALL, for the purposes of this specification, be “pertinent component elements”:

    1. All component elements in the top-level CellML infoset for the CellML model;

    2. All component elements referenced by import component elements (see 3.1 Interpretation of import elements) in the top-level CellML infoset; and

    3. All component elements which are descendants in the encapsulation digraph (see 3.9 Interpretation of encapsulation elements) of a pertinent component 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.

  1. 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 pertinent component 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:

\[ \begin{align}\begin{aligned}r_{total} = r_{tom} + r_{dick} + r_{harry}\\r_{total} = 99 + 0 + 10t\end{aligned}\end{align} \]

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:

\[ \begin{align}\begin{aligned}x = 0\\x = 1\end{aligned}\end{align} \]

Complicated over-definition is likewise valid:

\[ \begin{align}\begin{aligned}x + y = 1\\x - y = 3\\x * y = 12\end{aligned}\end{align} \]

Redundant information is valid, but (well) redundant:

\[ \begin{align}\begin{aligned}x = 1\\x = 1\\x = 1\end{aligned}\end{align} \]

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:

\[x = y + z\]

Unsolvable models and “bad” maths is valid CellML:

\[ \begin{align}\begin{aligned}x = 1 / 0\\x = \sqrt{-1}\end{aligned}\end{align} \]

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.

\[ \begin{align}\begin{aligned}x = 1\\x(0) = 2\end{aligned}\end{align} \]
  1. 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.

  1. 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>
  1. 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 or false. These constants can be used as the second ordinand of the piece operator, but cannot be used as input to operators expecting a numerical type.

  • piecewise

    • The inputs consist of piece and otherwise elements which have units as described in those sections.

    • The output of this operator has units given by the selected piece or otherwise 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 are dimensionless as well.

  • root, (degree)

    • The first input may have any units.

    • The degree element, if present, must have units of dimensionless.

    • 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 are dimensionless 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 the degree qualifier element inside the bvar 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.

  1. 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*powers

See 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>
  1. 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: marshmallow

See 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 to y [Amps] : invalid, conflicting unit reductions;

  • x [Volts] equivalent to y [millivolts] : valid, unit reductions are the same even though the scaling factor is different;

  • in the math element x [Volts] = y [Amps]: valid (but nonsense);

  • in the math element x [Volts] = 3 [Amps]: valid (but nonsense).

Interpretation of encapsulation elements

  1. 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.

  2. If a component_ref element appears as a child of another component_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 parent component_ref element, and to the node corresponding to the component referenced by the child component_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>
  1. 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.

  1. 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.

  1. 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.

  1. The “hidden set” for a component A SHALL be the set of all components B where component B is not in the encapsulated set for component A, and component B is not the encapsulation parent of component A, and component B is not in the sibling set for component A.

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 a component element or the model element itself.

  • 3.9.6 defines the “hidden set” of any component as those other component elements which are neither the parent, the children, nor the siblings of that current component 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 and JethrineBodine,

  • LukeClampett and AmosClampett, and

  • MyrtleClampett and JedClampett.

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 from EllyMayClampett (grandfather/grandchild)

  • AmosClampett is hidden from MyrtleClampett (uncle/niece)

  • PearlBodine is hidden from JedClampett (cousins)

  • GrannyMoses is hidden from LukeClampett (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

  1. 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.

    1. 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.

  1. 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:

    1. Variable A SHALL be the variable referenced by the encompassing connection element’s component_1 and this map_variables element’s variable_1 attribute; and

    2. Variable B SHALL be the variable referenced by the encompassing connection element’s component_2 and this map_variables element’s variable_2 attribute.

  2. For every map_variables element present in the CellML model, there SHALL be an arc in the variable equivalence network.

    1. One endpoint of the arc in the variable equivalence network SHALL be the node corresponding to variable A; and

    2. 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.

  1. CellML models MUST NOT contain any pair of map_variables elements which duplicates an existing arc in the variable equivalence network.

  2. 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>
  1. 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>
  1. 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>
  1. For a given variable, the “available interfaces” SHALL be determined by the value of the interface attribute on the corresponding variable element as follows:

    1. A value of public specifies that the variable has a public interface;

    2. A value of private specifies that the variable has a private interface;

    3. A value of public_and_private specifies that the variable has both a public and a private interface;

    4. A value of none specifies that the variable has no interface; or

    5. If the interface attribute is absent, then the variable has no interface.

  2. The “applicable interfaces” for variables A and B in components AA and BB respectively SHALL be defined as follows:

    1. 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.

    2. 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.

    3. 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.

  1. 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.

  1. 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.

    1. 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.

    2. Two tuples are considered identical if and only if both the unit name and exponent of each tuple are identical.

  2. 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 and ChristopherRobin have public interfaces between their mood and poohs_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 the mood variable in component Eeyore does not specify one, no mappings are permitted. For that connection to exist, the mood variable must have an interface type public.

  • Mapping C is not valid. The variable kangas_mood has explicitly specified that no mappings are possible by using the none interface type. For this mapping to be valid, the type needs to be public.

  • Mapping D is not valid. Because they are sibling components, the variables in ChristopherRobin and Kanga must both have the interface type of public 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 component Roo with a private interface. But if Mapping D is to be made valid, that same variable must maintain a public interface in order to access variables in its sibling component ChristopherRobin. It is for this reason that the public_and_private interface type exists. For Mappings D and E to be valid, the variable roos_mood in component Kanga must have an interface type of public_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>
  1. The variable elements in a CellML model SHALL be treated as belonging to a single “equivalent variable set”.

    1. 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.

    2. 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

  1. For the purposes of this section, we define the “reset variable” to be the variable referenced by a reset element’s variable attribute, and the “test variable” to be the variable referenced by its test_variable attribute.

  2. 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.

  1. 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.

    1. 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.

  1. For each reset item, determine whether its test criterion (the “when” idea above) has been met.

    1. If yes, the reset is said to be “active”.

    2. If not, it is “inactive”.

  2. Collect all active resets for a variable and its equivalent variables into a “variable active set”.

  3. For each variable, select the lowest order reset from the variable active set and designate it “pending”.

  4. Calculate, but do not apply, the update changes specified by each pending reset based on the current state of the model.

  5. 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.

  6. Test whether the set of variable values in the model has changed:

    1. If yes, repeat the steps above from (1) using the updated values as the basis for the tests.

    2. 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.

  1. 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.

  2. 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

  1. RFC 2119: Key words for use in RFCs to Indicate Requirement Levels https://www.ietf.org/rfc/rfc2119.txt

  1. XML Information Set (Second Edition) https://www.w3.org/TR/2004/REC-xml-infoset-20040204/

  1. Namespaces in XML 1.1 (Second Edition) https://www.w3.org/TR/xml-names11/

  1. Unicode® 13.0.0 https://www.unicode.org/versions/Unicode13.0.0/

  1. Extensible Markup Language (XML) 1.1 (Second Edition) https://www.w3.org/TR/xml11/

  1. 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:

  1. \(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.

  2. \(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)\).

alt goes here

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)\) :

  1. 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)\).

    1. 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.

    2. If only one reset rule is active for the same reset variable, select it.

  2. For each active reset rule, calculate the specified change, using the values \((x, t, p)\) to perform any calculation of new values.

  3. For each active reset rule, apply the calculated change.

  4. Test whether the system is in a new point \((x^\prime, t, p) \neq (x, t, p)\):

    1. If so, then let \((x, t, p) := (x^\prime, t, p)\) and repeat, starting from step 1.

    2. 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.

alt goes here

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.

alt goes here

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).

alt goes here

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.

alt goes here

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:

    1. At t = 1.0 we detect that A == 2, so the reset rule becomes active.

    2. The reset value is calculated to be 1.

    3. The reset value is applied.

    4. 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:

    1. 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

    1. At t = 100 we detect that x == 100, so rule 1 becomes active.

    2. The reset value for rule 1 is calculated to be 1.

    3. The reset value for rule 1 is applied to y.

    4. 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

    1. Since it is still true that x == 100, rule 1 is still active.

    2. The reset value is calculated,

    3. And applied.

    4. The state hasn’t changed: \((x^\prime, t, p) = (x, t, p)\), so reset rule 1 processing halts.

  • Cycle

    1. At t = 101 we detect that x == 101, so rule 2 becomes active.

    2. The reset value for rule 2 is calculated to be 0.

    3. The reset value for rule 2 is applied to y.

    4. The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), so restart.

  • Cycle

    1. Since it is still true that x == 101, rule 2 is still active.

    2. The reset value is calculated,

    3. And applied.

    4. 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

    1. At t = 0 we detect that x == 0, so rule 1 becomes active.

    2. The reset value for rule 1 is calculated to be 1.

    3. The reset value for rule 1 is applied to y.

    4. The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), we restart at step 1.

  • Cycle 2

    1. Since it is still true that x == 0, rule 1 is still active.

    2. The reset value for rule 1 is (again) calculated to be 1.

    3. The reset value for rule 1 is (again) applied to y.

    4. The state hasn’t changed: \((x^\prime, t, p) == (x, t, p)\), so reset rule 1 processing halts.

  • Cycle 3

    1. 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

    1. At t = 1 we detect that x == 1, so rule 2 becomes active.

    2. The reset value for rule 2 is calculated to be 0.

    3. The reset value for rule 2 is applied to y.

    4. The system is now in a new state: \((x^\prime, t, p) \neq (x, t, p)\), so restart.

  • Cycle 5

    1. Since it is still true that x == 1, rule 2 is still active.

    2. The reset value for rule 2 is calculated (still) to be 0.

    3. And reset value for rule 2 is applied to y.

    4. The state hasn’t changed: \((x^\prime, t, p) == (x, t, p)\), so reset rule 2 processing halts.

  • Cycle 6

    1. 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