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