3.8. Interpretation of math
elements¶
The following
component
elements SHALL, for the purposes of this specification, be “pertinent component elements”:All
component
elements in the top-level CellML infoset for the CellML model;All
component
elements referenced byimport component
elements (see 3.1 Interpretation of import elements) in the top-level CellML infoset; andAll
component
elements which are descendants in the encapsulation digraph (see 3.9 Interpretation of encapsulation elements) of a pertinentcomponent
element.
See more
What is a “pertinent component”?
Pertinent components are those which together form the entirety of the model.
They could be locally defined within the model
itself, imported from a separate file, or a dependency within the encapsulated set of an imported component.
The example below describes a game of cricket in the backyard of a boy called Tom (defined locally).
He imports a boy called Harry from next door, but Harry’s dog Dick comes along too as an implicit import because the component DickTheDog
is encapsulated as a child of the component Harry
in the Neighbours.cellml
file.
All three components Tom
, DickTheDog
, and Harry
are “pertinent” to the BackyardCricket
model.
The component George
, also in the Neighbours.cellml
file is not pertinent, as it is not within the encapsulated set of the imported component Harry
.
file: MyHouse.cellml
└─ model: BackyardCricket
└─ component: FirstGame
├─ component: Tom (locally defined)
└─ component: Harry <╴╴╴╴╴╴╴╴╴╴╴╴┐
└─ component: DickTheDog ╷
explicitly importing Harry will
file: Neighbours.cellml implicitly import DickTheDog
└─ model: HarrysHouse ╵
├─ component: Harry ╴╴╴╴╴╴╴╴╴╴╴╴┬╴╴╴╴┘
│ └─ component: DickTheDog ╴╴╴╴┘
└─ component: George
See CellML syntax example
In file: MyHouse.cellml
<model name="BackyardCricket" >
<!-- Pertinent: A locally defined component. -->
<component name="Tom" />
<!-- Pertinent: An explicitly imported component. -->
<import href="Neighbours.cellml">
<component component_ref="Harry" name="Harry" />
</import>
<!-- Pertinent: Another locally-defined component. -->
<component name="FirstGame" />
<!-- The local encapsulation structure does not affect which components are pertinent. -->
<encapsulation>
<component_ref component="FirstGame" >
<component_ref component="Tom" />
<component_ref component="Harry" />
</component_ref>
</encapsulation>
</model>
In file: Neighbours.cellml
<model name="HarrysHouse" >
<component name="Harry" />
<!-- Pertinent: An implicitly imported component, pertinent because of its presence
in the encapsulated set of an imported component. -->
<component name="DickTheDog" />
<!-- Not pertinent: George is not a pertinent component item to the
BackyardCricket model as it is neither explicitly nor implicitly imported. -->
<component name="George" />
<!-- The encapsulation set means that DickTheDog is a pertinent component item,
as it is imported at the same time as the component Harry is imported. -->
<encapsulation>
<component_ref component="Harry" >
<component_ref component="DickTheDog" />
</component_ref>
</encapsulation>
</model>
After we know which components are pertinent, we can retrieve their mathematical contents (i.e.: the pertinent components’ math
elements) and use these in the broader BackyardCricket model.
Every MathML element in the CellML model which appears as a direct child of a MathML
math
element, which in turn appears as a child of a pertinentcomponent
element, SHALL be treated, in terms of the semantics of the mathematical model, as a statement which holds true unconditionally.
See more
Understanding how the mathematics works
The mathematics of a mathematical model is a collection of statements which are held to be true at all times.
These are distinct from initial conditions of a model (specified using the initial_value
attribute on variable
elements) which are only true initially.
You can read more about initialisation in 3.6 Interpretation of initial_value attributes page and in the section below this one.
The collection of mathematical statements in a CellML model is the set of children of all math
elements inside its “pertinent components” (as explained in the previous block).
The example from the previous point is extended below in pseudocode, with the full CellML code beneath the link below.
The final output from the model - the total runs scored - is found by reducing all of the math
elements from all pertinent components in the model, whether or not those components interact. In this example, the same mathematical situation could be written:
where \(r\) is the number of runs, and \(t\) is time.
model: BackyardCricket
│
└─ component: FirstGame
│ ├─ variable: dicks_runs <╴╴╴╴╴╴┐
│ ├─ variable: harrys_runs <╴╴┐ ╷
│ ├─ variable: toms_runs <╴┐ ╷ ╷
│ ├─ variable: time ╷ ╷ ╷
│ └─ math: total_runs = toms_runs + dicks_runs + harrys_runs
│ ╵ ╵ ╵
├─ component: Tom ╵ ╵ ╵
│ ├─ variable: runs ╴╴╴╴╴╴╴┘ ╵ ╵
│ └─ math: runs = 99 ╵ ╵ equivalent
│ ╵ ╵ variables
└─ component: Harry (imported) ╵ ╵
│ ├─ variable: runs ╴╴╴╴╴╴┘ ╵
│ ├─ variable: time ╵
│ ├─ variable: dicks_runs ╴╴╴┤
│ └─ math: runs = 10*time ╷
│ ╷
└─ component: DickTheDog ╷
├─ variable: runs ╴╴╴╴╴╴╴╴┘
└─ math: runs = 0
See CellML syntax example
In file: MyHouse.cellml
<model name="BackyardCricket" >
<!-- The local component Tom now has a score, measured by the variable "runs".
This score is constant for all of time. Tom will never get his century! -->
<component name="Tom">
<variable name="runs" units="dimensionless" />
<math>
<apply><eq/>
<ci>runs</ci>
<cn cellml:units="dimensionless">99</cn>
</apply>
</math>
</component>
<import href="Neighbours.cellml">
<component component_ref="Harry" name="Harry" />
</import>
<!-- The total tally for the game is stored in the variable "total". -->
<component name="FirstGame">
<variable name="total" units="dimensionless" />
<variable name="toms_runs" units=" dimensionless" />
<variable name="harrys_runs" units=" dimensionless" />
<variable name="dicks_runs" units=" dimensionless" />
<math>
<apply><eq/>
<ci>total</ci>
<apply><plus/>
<ci>toms_runs</ci>
<ci>harrys_runs</ci>
<ci>dicks_runs</ci>
</apply>
</apply>
</math>
</component>
<!-- Connections to report the runs from each player are established. -->
<connection component_1="FirstGame" component_2="Tom" >
<map_variables variable_1="toms_runs" variable_2="runs" />
</connection>
<!-- Since component "DickTheDog" is too distant in the encapsulation structure to be
visible to the "FirstGame" component, any runs scored by the dog must be passed
through Harry's component. -->
<connection component_1="FirstGame" component_2="Harry" >
<map_variables variable_1="harrys_runs" variable_2="runs" />
<map_variables variable_1="dicks_runs" variable_2="dicks_runs" />
</connection>
<encapsulation>
<component_ref component="FirstGame" >
<component_ref component="Tom" />
<component_ref component="Harry" />
</component_ref>
</encapsulation>
</model>
In file: Neighbours.cellml
<model name="HarrysHouse" >
<component name="DickTheDog">
<variable name="runs" units="dimensionless" />
<math>
<!-- This statement sets DickTheDog's score to 0 for all time.
He's a dog: potentially a good outfielder, but a terrible batsman. -->
<apply><eq/>
<ci>runs</ci>
<cn cellml:units="dimensionless">0</cn>
</apply>
</math>
</component>
<component name="Harry">
<variable name="time" units="minute" />
<variable name="runs" units="dimensionless" />
<variable name="dicks_runs" units="dimensionless" />
<math>
<!-- This statement represents DickTheDog running away with the ball,
enabling Harry to score an ever-increasing number of runs. -->
<apply><eq/>
<ci>runs</ci>
<apply><times/>
<cn cellml:units="per_minute">10</cn>
<ci>time</ci>
</apply>
</math>
</component>
<!-- This is not a pertinent component to the BackyardCricket model. -->
<component name="George" />
<!-- A connection is established between Harry and DickTheDog to enable sharing of their run tally. -->
<connection component_1="Harry" component_2="DickTheDog" >
<map_variables variable_1="dicks_runs" variable_2="runs" />
</connection>
...
</model>
Understanding how and when the mathematics doesn’t work
It’s possible to write valid CellML that does not represent valid mathematics.
You can think of this like correctly spelling a set of words which together do not form a meaningful sentence.
Some examples of valid versus valid-but-nonsense math
elements’ contents are shown below.
Simple over-definition is valid, but will result in behaviour that is hard to interpret meaningfully:
Complicated over-definition is likewise valid:
Redundant information is valid, but (well) redundant:
Under-definition at a localised component level is both valid and useful, as you may need to connect to other components in order to know the value of the variables the maths statements are using. Models which overall have insufficient definition are also valid, but clearly won’t be useful or solvable:
Unsolvable models and “bad” maths is valid CellML:
Conflicting information arising from initialising variables which are not state variables will have an outcome which depends on how the implementation software interprets the condition. It is not invalid CellML, but - as with other forms of over-definition - may not result in the same interpretation between software implementations.
Units referenced by a
units
attribute SHALL NOT affect the mathematical interpretation of the CellML model.
See more
Understanding how the units work
Within a component:
We know that units in real life make a big difference, but within a CellML component, they don’t.
Units in equations are provided to help the user find bugs, and each variable
element has to specify a corresponding units
element, but these combinations don’t affect the validity of the math
element.
They do make a difference to how your model may to be interpreted, and can help you to find errors or inconsistencies in your mathematical definitions.
Some examples are shown below.
Constants and variables in an equation have different units: this is not invalid CellML, but doesn’t make any mathematical sense.
<variable name="lunch" units="omelette" /> ... <apply><eq/> <ci>lunch</ci> <apply><plus/> <cn cellml:units="egg">2</cn> <cn cellml:units="cheese">5</cn> <cn cellml:units="milk">0.1</cn> </apply> </apply>
Exponents have units other than
dimensionless
: again, not invalid CellML, but mathematical nonsense.
<variable name="E" units="joule" /> <variable name="m" units="kilogram" /> <variable name="c" units="metres_per_second" /> ... <apply><eq/> <ci>E</ci> <apply><times/> <ci>m</ci> <apply></power> <ci>c</ci> <cn cellml:units="anything_not_dimensionless">2</cn> </apply> </apply> </apply>A complete list of the mathematically valid units for different MathML operations is available under the link below.
Show units guidelines for MathML operations
Units guidelines for MathML operations
eq
,neq
,gt
,lt
,geq
,leq
,and
,or
,xor
,not
The inputs to these operators should have equivalent units.
The result of these operators is not a number with a unit, but one of the logical constants
true
orfalse
. These constants can be used as the second ordinand of thepiece
operator, but cannot be used as input to operators expecting a numerical type.
piecewise
The inputs consist of
piece
andotherwise
elements which have units as described in those sections.The output of this operator has units given by the selected
piece
orotherwise
element child.
piece
, (otherwise
)
The first input may have any units.
The second input is a relational statement, which does not have units.
The output of each operator has the same units as their first inputs.
exp
,exponentiale
,ln
,log
,logbase
The input of each operator must have units of
dimensionless
.The output of each operator has units of
dimensionless
.
sin
,cos
,tan
,sec
,csc
,cot
,sinh
,cosh
,tanh
,sech
,csch
,coth
,arcsin
,arccos
,arctan
,arccosh
,arccot
,arccoth
,arccsc
,arccsch
,arcsec
,arcsech
,arcsinh
,arctanh
The input of each operator must have units of
dimensionless
.The output of each operator has units of
dimensionless
.
plus
,minus
,min
,max
The inputs of each operator must have equivalent units.
The output of each operator has the same units as its inputs.
abs
,floor
,ceiling
The inputs may have any units.
The output of each operator has the same units as its input.
times
The inputs may have any units.
The output has units given by the product of the units of the inputs. This product may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
divide
,rem
The inputs may have any units.
The output of each operator has units given by the quotient of the units on the first and second inputs. This quotient may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
power
The first input may have any units.
The second input must have units of
dimensionless
.The output has units given by the units of the first input raised to the power of the second input.
If the first input has units of
dimensionless
, the output units aredimensionless
as well.
root
, (degree
)
The first input may have any units.
The
degree
element, if present, must have units ofdimensionless
.The output has units given by the units on the first input raised to the reciprocal of the value of the
degree
qualifier element (the default value of which is 2.0).If the first input has units of
dimensionless
, the output units aredimensionless
as well.
diff
, (bvar
,degree
)
The input may have any units.
The output has units that are the quotient of the units of the input over the units of the term in the
bvar
qualifier element raised to the value of thedegree
qualifier element inside thebvar
qualifier element (the default value of which is 1.0). This quotient may be simplified as long as the unit reduction is maintained (see 3.3.3 in 3.3 Interpretation of units elements).
Between components: Components were designed to promote modularity and reuse of models, so it’s important that those re-users understand what they’re getting into. This is why equivalent variables (those connected across components) must have the same unit reduction, so that whatever the inner workings of a component are, the external users of that component are able to interpret them correctly.
The only situation in which units
items are compared to one another is between equivalent variables, i.e.: the variable_1
and variable_2
attributes of a map_variables
element.
Here, both of the variable
elements referenced must have the same unit reduction, though not necessarily the same multiplication factor.
Some examples of these are shown below.
Any custom or built-in units with differing scaling factors between connected variables: valid, as the unit reduction is the same, but the resulting mathematics will need to be interpreted carefully!
model: DCUniverse ├─ component: Metropolis │ └─ variable: Superman (units = megapowers) <╴╴┐ │ ╷ │ connected variables ├─ component: Smallville ╵ │ └─ variable: ClarkKent (units = micropowers) ╴┘ │ └─ units: powers ├─ units: micropowers = 0.000001*powers └─ units: megapowers = 1,000,000*powersSee CellML syntax
<model name="DCUniverse"> <!-- Defining a custom base unit called "powers". --> <units name="powers" /> <!-- Creating the derived custom units with different prefixes, mega and micro. --> <units name="megapowers" > <unit units="powers" prefix="mega" /> </units> <units name="micropowers"> <unit units="powers" prefix="micro" /> </units> <!-- The variable "Superman" in component "Metropolis" has units of "megapowers". --> <component name="Metropolis"> <variable name="Superman" units="megapowers" /> </component> <!-- The variable "ClarkKent" in component "Smallville" has units of "micropowers". --> <component name="Smallville"> <variable name="ClarkKent" units="micropowers" /> </component> <!-- The connection is valid, because the unit reduction is the same, even though the multiplication factor between the two variables is different. --> <connection component_1="Metropolis" component_2="Smallville"> <map_variables variable_1="Superman" variable_2="ClarkKent" /> </connection> </model>
Any custom of built-in units with differing unit reduction tuples between connected variables: invalid, as it contradicts point 3.10.6 in 3.10 Interpretation of map_variables elements. Please see the third informative block in 3.3 Interpretation of units elements section for more discussion and examples of unit reductions.
model: DCUniverse ├─ component: FarFromKryptonite │ └─ variable: Superman (units = megapowers) <╴╴╴╴┐ │ ╷ │ connection is now invalid ├─ component: NearToKryptonite ╵ │ └─ variable: ClarkKent (units = marshmallow) ╴╴╴┘ │ ├─ units: powers │ └─ units: megapowers = 1,000,000*powers │ └─ units: marshmallowSee CellML syntax
<model name="DCUniverse"> <units name="powers" /> <units name="megapowers" > <unit units="powers" prefix="mega" /> </units> <!-- Creating a new base unit called "marshmallow".--> <units name="marshmallow" /> <!-- The variable "Superman" in component "FarFromKryptonite" has units of "megapowers". --> <component name="FarFromKryptonite"> <variable name="Superman" units="megapowers" /> </component> <!-- The variable "ClarkKent" in component "NearToKryptonite" has units of "marshmallow". --> <component name="NearToKryptonite"> <variable name="ClarkKent" units="marshmallow" /> </component> <!-- The connection is invalid, because the unit reduction not the same. --> <connection component_1="FarFromKryptonite" component_2="NearToKryptonite"> <map_variables variable_1="Superman" variable_2="ClarkKent" /> </connection> </model>
In summary, the only place in which units can cause validation errors related to variables is between equivalent variables (variables connected using connection
and map_variables
elements):
x
[Volts] equivalent toy
[Amps] : invalid, conflicting unit reductions;x
[Volts] equivalent toy
[millivolts] : valid, unit reductions are the same even though the scaling factor is different;in the
math
elementx
[Volts] =y
[Amps]: valid (but nonsense);in the
math
elementx
[Volts] = 3 [Amps]: valid (but nonsense).