Grammar#
gotranx uses a domain specific language (DSL), that is implemented using lark, and you can find the complete grammar here.
In this section, we will try to describe the grammar, and how you can write your own .ode files to define your ODEs using this grammar.
Basic ODE file#
An example .ode file called lorentz.ode could look as follows
# Define parameters
parameters(sigma=12.0, rho=21.0, beta=2.4)
# Define states
states(x=1.0, y=2.0, z=3.05)
# Define expressions
dx_dt = sigma * (y - x)
a = rho - z
dy_dt = x * a - y
dz_dt = x * y - beta * z
We will now go through the basic building block for creating an ODE
parametersallows users to define parameters in the ODE. These are constant that the a user can provide as arguments. For exampleparameters(sigma=12.0, rho=21.0, beta=2.4)
will create three parameters
sigma,rhoandbetawith a default value of12,21.0and2.4respectively.statesdefines the state variables which are the variables you want to solve for. For examplestates(x=1.0, y=2.0, z=3.05)
will define three state variables
x,yandzwho’s default initial condition will be set to1,2and3.0respectively.expressionsallows users to define mathematical expressions using parameters and other variables. You can also define new variables as an expression. In this section you also need to specify the the state derivatives of all the state variables. For the state derivatives you need the variables name to bed{STATE_NAME}_dt, e.gdx_dtfor the state derivative ofx. In this case we could for example havedx_dt = sigma * (y - x) a = rho - z dy_dt = x * a - y dz_dt = x * y - beta * z
In this context,
awill be referred to as an intermediate variable.Comments can be added on separate lines by starting the line
#, for example# Define parameters
Variables can only be defined once#
An important thing to note is that once you have defined a variable you cannot redefine it, so for example the following expression is not valid
x = 1
y = 2 * x
x = 3
Operators and symbols#
Mathematical operators#
The following unary mathematical operators are supported
expcossintanacosasinatanabsfloorlnlogsqrt
The following binary mathematical operators are supported
Mod
For example
x = abs(1.0 - exp(4))
Numbers#
A basic number can be written as e.g
x = 1 # Will be casted to an integer
y = 1.0 # Will be casted to a float
z = 1 / 4 # Will be cased to a rational number
w = (2 * 3) / 3 # Will be cased to an expression
It is also possible to use scientific notation using either uppercase of lowercase e, e.g the following numbers are equivalent
x = 100
x = 1e2
x = 1E2
Similarly you can also use negative exponents, e.g the following numbers are equivalent
x = 0.01
x = 1e-2
x = 1E-2
Mathematical constants#
There is currently only one reserved constant with is pi. This means that you can e.g write
x = cos(2 * pi)
without the need to define pi in advance
Conditional operators and boolean operators#
The following boolean operators are supported
Ltwhich is equivalent to<Gtwhich is equivalent to>Lewhich is equivalent to<=Gewhich is equivalent to>=Eqwhich is equivalent to==NotAndOr
It is also possible to use the conditionals using the Conditional function (there is also a continuous version called ContinuousConditional), which has the following syntax
Conditional(boolean_expression, true_value, false_value)
For example the Heaviside step function
can be defined as follows
H = Conditional(Geq(x, 0), 1, 0)
This would be similar to implemented an if-else statement, e.g
if x >= 0:
H = 1
else:
H = 0
We could also have a conditional with three value, e.g
which would be equivalent to and if-elif-else statement, e.g
if x > 0:
H = 1
elif x == 0:
H = 0.5
else:
H = 0
but in this case we would need to nest conditionals together, for example
H = Conditional(Gt(x, 0), 1, Conditional(Eq(x, 0.0), 0.5, 0.0))
or another solution could be
H = Conditional(Gt(x, 0), 1, Conditional(Lt(x, 0.0), 0.0, 0.5))
Implementing min and max#
The operations min and max can be implemented in terms of Conditional, because
f = min(x, y)
is equivalent to
if x <= y:
f = x
else:
f = y
So f = min(x, y) could be implemented as
f = Conditional(Le(x, y), x, y)
Similarly f = max(x, y) can be implemented as
f = Conditional(Ge(x, y), x, y)
Advanced usage#
Adding components, units and descriptions#
If you have a large system of ODE’s it might be good to group parts that together in the same group, which we will refer to as components.
states("membrane",
V=ScalarParam(-87, unit="mV", description="")
)
states("sodium_channel_h_gate",
h=ScalarParam(0.8, unit="1", description="")
)
states("sodium_channel_m_gate",
m=ScalarParam(0.01, unit="1", description="")
)
states("potassium_channel_n_gate",
n=ScalarParam(0.01, unit="1", description="")
)
parameters("membrane",
Cm=ScalarParam(12.0, unit="uF", description="")
)
parameters("leakage_current",
E_L=ScalarParam(-60.0, unit="mV", description=""),
g_L=ScalarParam(75.0, unit="uS", description="")
)
parameters("sodium_channel",
E_Na=ScalarParam(40.0, unit="mV", description=""),
g_Na_max=ScalarParam(400000.0, unit="uS", description="")
)
expressions("sodium_channel_h_gate")
alpha_h = 170.0*exp((-V - 1*90.0)/20.0) # S/F
beta_h = 1000.0/(exp((-V - 1*42.0)/10.0) + 1.0) # S/F
dh_dt = alpha_h*(1.0 - h) - beta_h*h
expressions("sodium_channel_m_gate")
alpha_m = (100.0*(-V - 1*48.0))/(exp((-V - 1*48.0)/15.0) - 1*1.0) # S/F
beta_m = (120.0*(V + 8.0))/(exp((V + 8.0)/5.0) - 1*1.0) # S/F
dm_dt = alpha_m*(1.0 - m) - beta_m*m
expressions("potassium_channel_n_gate")
alpha_n = (0.1*(-V - 1*50.0))/(exp((-V - 1*50.0)/10.0) - 1*1.0) # S/F
beta_n = 2.0*exp((-V - 1*90.0)/80.0) # S/F
dn_dt = alpha_n*(1.0 - n) - beta_n*n
expressions("potassium_channel")
g_K1 = 1200.0*exp((-V - 1*90.0)/50.0) + 15.0*exp((V + 90.0)/60.0) # uS
g_K2 = 1200.0*n**4.0 # uS
i_K = (V + 100.0)*(g_K1 + g_K2) # nA
expressions("sodium_channel")
g_Na = g_Na_max*(h*m**3.0) # uS
i_Na = (-E_Na + V)*(g_Na + 140.0) # nA
expressions("leakage_current")
i_Leak = g_L*(-E_L + V) # nA
expressions("membrane")
dV_dt = (-(i_Leak + (i_K + i_Na)))/Cm # mV