Math Expressions
Mathematical expressions {math-expr}
are permitted on different arguments of the
configuration options. They consist of a string
that when interpreted and evaluated returns a numeric value. Such expressions may contain typical math
operations such as +
, -
, *
, sin
, tan
, sqrt
, etc.
The example below initializes the variable u
with and sets its diffusion coefficient to .
[model.scalar_value.u]
initial.expression = 1.0 + 2e-10
cross_diffusion.u.expression = sqrt(2e-10)
Note how the contents of these arguments need to be understood by a suitable math interpreter.
The exact syntax permitted within math expressions {math-expr}
depends on the parser type used to interpret
the expression. Every expression may be instructed to be interpreted with a different parser by setting [*.]parser_type={enum}
. The possible parsers are:
'ExprTk'
'ExprTk'
The C++ Mathematical Expression Toolkit Library. Focuses in functionality and performance.
'MuParser'
'MuParser'
A fast math parser library. Available in most package managers.
'SymEngine'
'SymEngine'
A symbolic manipulation library. Best known for its python bindings: SymPy
.
'SymEngineSBML'
'SymEngineSBML'
A SBML flavored syntax of the 'SymEngine'
parser.
Some parsers may not be available depending on how dune-copasi
is compiled. To see the available parsers use the --parser-list
command.
Every expression in {math-expr}
is compiled independently. This means that different parser types may be used in the same model definition. This is helful when the syntax of one parser is more convenient to write one expression. For example, the
ExprTk
parser allows the usage of ternary conditional operator cond ? expr1 : expr2
whereas SymEngine
does not:
[parser_context.pulse]
type = function
expression = t, t0, dt: abs(t-t0) < dt ? 1 : 0
parser_type = ExprTk
[model.scalar_value.u]
reaction.expression = 1e10 + pulse(time, 10, 1)
reaction.parser_type = SymEngine
Keywords
Math expressions may be evaluated in many different contextual environments, such as, in the initialization of variables, a coefficient interpretation, or as an aid to define the cells that belong to a comartment. Depending on the context, several keywords are defined in order to help expressing the desired mathematical model. These keywords are declared and defined in the following way:
Contextual Transient Keywordβ
Whenever the context of the evaluation is transient, the time
keyword will evaluate to the corresponding simulation time .
In other words,
Contextual Domain Keywordsβ
Whenever an expression is evaluated at a position then this position is also available within the {math-expr}
. Such position is made available through the position_[x|y|z]
keywords such that
where is the extension of into .
We assume that the domain is covered by a mesh consisting of elements which are closed sets satisfying
The nonempty intersections of codimension 1 form the interior skeleton . Each intersection is equipped with a unit normal vector pointing from to . The intersections of an element with the domain boundary form the set of boundary intersections . Each boundary intersection is equipped with a unit normal vector which coincides with the unit outer normal to the domain.
Furthermore, the contextual domain evaluation is always associated to a grid element . Its properties are also expossed within the parser as:
In the cases where we also have that its unit outer normal vector is exposed with the keywords normal_[x|y|z]
such that
where is the extension of into .
Contextual Scalar Field Keywordsβ
There are cases where the evaluation of {math-expr}
is made when the results of the scalar values {var}
(or a trial function of them) are known. In such cases, the value of {var}
evaluated at position is made available thoruhg the parsers. Additionally, its gradient {var}
is also represented by the grad_{var}_[x|y|z]
tokens.
The configuration file to represent the system of ordinary differential equations
with the reaction networks on the form of
will contain something similar to this:
[model.scalar_field.u]
storage.expression = 1
reaction.expression = z*u^2*(1-u) - u
reaction.jacobian.u.expression = u*z*(2-3*u)-1
reaction.jacobian.z.expression = (1-u)*u^2
[model.scalar_field.z]
storage.expression = 1
reaction.expression = (u <= 0.1) ? (1 - z)/1.25 : -z
reaction.jacobian.z.expression = (u <= 0.1) ? -1/1.25 : -1
Notice how the tokens u
and z
are allowed in each {math-expr}
across different scalar field sub-sections of *.u
and *.z
. This allows to express non-linearities in a natural form.
Custom Keywordsβ
parser_context.{tkn}.type={enum}
parser_context.{tkn}.{...}={...}
Independently of the evaluation context, you are allowed to inject keywords into the parser in order to express mathematical expressions easier. The defined keywords will be defined and allowed to be used within math-expr
definitions.
Constantsβ
parser_context.{tkn}.type='constant'
parser_context.{tkn}.value={float}
Defines a keyword {tkn}
that when evaluated gets replaced by the constant contained in {float}
.
[parser_context.water_diffusion]
type = constant
value = 2.299E10β9
is equivalent to
Function Math Expressionsβ
parser_context.{tkn}.type='function'
parser_context.{tkn}.expression={func-expr}
parser_context.{tkn}.parser_type={enum}
Declares a keyword {tkn}
than may be used as a function within the parsers. The definition of the function starts with up to 4 comma separated string arguments followed by a colon and a math expression.
{args} := {arg0}[, {arg1}[, {arg2}[, {arg3}]]]
{func-expr} := {args}: {math-expr}
The math expression {math-expr}
is allowed to use the arguments {args}
as numerical values and any other custom defined keywords exceptuating other function keywords.
This example defines a keyword pulse
that may be used in other math expression config option argument to evaluate {math-expr}
when provided with 3 arguments.
[parser_context.pulse]
type = function
expression = t, t0, dt: abs(t-t0) < dt ? 1 : 0
is equivalent to
parser_context.{tkn}.interpolate={bool}
parser_context.{tkn}.domain.{arg}={float-pair}
parser_context.{tkn}.intervals={integer}
parser_context.{tkn}.out_of_bounds={enum}
In cases where {math-expr}
is very expensive to compute and the function has one argument, these options allow to replace the function definition with a linear interpolation of {math-expr}
.
This example defines a keyword my_exp
referring to an interpolation of exp(x)
evaluated in 100
sub-intervals between the domain values 0
and 10
.
[parser_context.my_exp]
type = function
expression = x: exp(x)
interpolate = true
domain.x = 0 10
intervals = 100
out_of_bounds = error
The interpolation may be disabled by setting interpolate=false
, in which case exp(x)
will be compiled and evaluated as any other mathematical expression.
A {math-expr}
with 'function'
type is not allowed to contain other custom keywords defined as 'function'
type. This means that recursive and composition of functions is not allowed.
[parser_context.factorial]
type = function
expression = n: (n > 0) ? n * factorial(n-1) : n
# error: 'factorial' keyword is not known
[parser_context.f]
type = function
expression = x, y: sin(x) * cos(y)
[parser_context.g]
type = function
expression = x: f(x, x-1)
# error: 'f' keyword is not known
There is a maximum limit to the number of functions may can be defined when the {math-expr}
is compiled using [*.]parser_type='MuParser'
. This limit is severely reduced when the assembly is made in concurrent mode. We recommend using other parsers when defining functions.
Random Fieldβ
parser_context.{tkn}.type='random_field'
parser_context.{tkn}.{parafields-key}={parafields-value}
These options generate a Gaussian random field based on circulant embedding using parafields and declares it as a function with the keyword {tkn}
. The number of arguments of such function depends on the dimension of the grid used to generate the random field. All parameters {parafields-key}={parafields-value}
under the parser_context.{tkn}
subsection will be forwarded to the parafields-core
engine.
The example below shows the definition of the keyword my_rng
in the parsers as a 2D function with the contents of a random field. Later, the keyword my_rng
is used within a math expression to initialize the variable u
using the contextual domain keywords position_x
and position_y
.
[parser_context.my_rng]
type = random_field
grid.extensions = 1.0 1.0
grid.cells = 1000 1000
randomField.transform = logNormal
stochastic.corrLength = 0.10
stochastic.covariance = exponential
stochastic.variance = 0.2
[model.scalar_field.u]
initial.expression = my_rng(2*position_x, 2*position_y)
If the resulting function {tkn}
is evaluated outside the domain values, the
arguments will be clamped to
the nearest valid point in the domain.
This option is only available when dune-copasi
is compiled with parafields.
1D Linear Interpolationβ
parser_context.{tkn}.type='interpolation'
parser_context.{tkn}.domain={float-list}
parser_context.{tkn}.range={float-list}
A 1D function with a linear interpolation may be generated from of domain and range pairs.
A configuration file with the following input
[parser_context.f]
type = interopation
domain = 0 1 2 3 4 5 6
range = 0 0.8415 0.9093 0.1411 β0.7568 β0.9589 β0.2794
represents a function f(x)
with this graphical representation:
If the resulting function {tkn}
is evaluated outside the domain values, the
arguments will be clamped to
the nearest valid point in the domain.
Images (TIFF Format)β
parser_context.{tkn}.type='tiff'
parser_context.{tkn}.path={path}
Reads an image file with tiff
format and makes it available as a 2D function expression with the {tkn}
token.
Images with grayscale values of 8
, 16
, 32
, and 64
bits are supported.
The example below shows the definition of the keyword my_image
in the parsers as a 2D function with the contents of the file in path/to/file.tif
. Later, the keyword my_image
is used within a math expression to initialize the variable u
using the contextual domain keywords position_x
and position_y
.
[parser_context.my_image]
type = tiff
path = path/to/file.tif
[model.scalar_field.u]
initial.expression = my_image(2*position_x, 2*position_y)
Grid Cell Data (TXT Format)β
grid.cell_data.{dtkn}.path={prefix}
The keywords {dtkn}
defined by grid.cell_data.{dtkn}.path={prefix}
will be additionally available within the math expressions that are under a domain context. When evaluated it will contain the data defined within the {prefix}
file.
Reserved Keywordsβ
The following keywords are reserved to have special meaning within the program:
Keyword | Description |
---|---|
no_value | Indicates that the result of an expression does not represent a numeric value |
Additionally to those defined here, every underlying parser has its own set of keywords that are reserved. Visit the documentation of your preferred parser to learn more about its syntax and its reserved keywords.