Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions book/src/functions.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Pre-defined functions
# Pre-defined functions & variables

## Pre-defined functions

The DiffSL supports the following mathematical functions that can be used in an expression:

Expand All @@ -7,25 +9,35 @@ The DiffSL supports the following mathematical functions that can be used in an
* `cos(x)` - cosine of x
* `tan(x)` - tangent of x
* `exp(x)` - exponential of x
* `tanh(x)` - hyperbolic tangent of x
* `sinh(x)` - hyperbolic sine of x
* `cosh(x)` - hyperbolic cosine of x
* `arcsinh(x)` - inverse hyperbolic sine of x
* `arccosh(x)` - inverse hyperbolic cosine of x
* `log(x)` - natural logarithm of x
* `log10(x)` - base-10 logarithm of x
* `sqrt(x)` - square root of x
* `abs(x)` - absolute value of x
* `sigmoid(x)` - sigmoid function of x
* `heaviside(x)` - Heaviside step function of x

You can use these functions as part of an expression in the DSL. For example, to define a variable `a` that is the sine of another variable `b`, you can write:

```
```diffsl
b { 1.0 }
a { sin(b) }
```

# Pre-defined variables
## Pre-defined variables

There are two predefined variables in DiffSL. The first is the scalar `t` which is the current time, this allows the equations to be written as functions of time. For example

```diffsl
F_i { t + sin(t) }
```

The only predefined variable is the scalar `t` which is the current time, this allows the equations to be written as functions of time. For example
The second is the scalar `N` which is the current model index, this allows us to write hybrid models with multiple ODE systems in the same file. For example

```diffsl
F_i { g_i[N] * x }
```
F_i {
t + sin(t)
}
```
25 changes: 11 additions & 14 deletions book/src/inputs_outputs.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Inputs & Outputs

Often it is useful to parameterize the system of equations using a set of input parameters. It is also useful to be able to extract certain variables from the system for further analysis.
Often it is useful to parameterize the system of equations using a set of input parameters. It is also useful to be able to extract certain outputs from the system for further analysis.
In this section we will show how to specify inputs and outputs in the DiffSL language.

## Specifying inputs
Expand All @@ -9,43 +9,40 @@ We can override the values of any scalar variables by specifying them as input
variables. To do this, we add a line at the top of the code to specify that
these are input variables:

```
```diffsl
in { k = 1.0 }
u { 0.1 }
F { k * u }
```

Here we have specified a single input parameter `k` that is used in the RHS function `F`.
The value of `k` is set to `1.0` in the code, but this value is only a default, and can be overridden by passing in a value at solve time.
Here we have specified a single input parameter `k` that is used in the RHS function `F`.
The value of `k` is set to `1.0` in the code, but this value is only there to specify the shape of the element, and will be overridden by passing in a value at solve time.

We can use input parameters anywhere in the code, including in the definition of other input parameters.

```
```diffsl
in { k = 1.0 }
g { 2 * k }
F { g * u }
```

or in the intial conditions of the state variables:

```
```diffsl
in { k = 1.0 }
u_i {
x = k,
}
u_i { x = k }
F { u }
```


## Specifying outputs

We can also specify the outputs of the system. These might be the state
variables themselves, or they might be other variables that are calculated from
the state variables.
the state variables.

Here is an example where we simply output the elements of the state vector:

```
```diffsl
u_i {
x = 1.0,
y = 2.0,
Expand All @@ -56,11 +53,11 @@ out_i { x, y, z }

or we can derive additional outputs from the state variables:

```
```diffsl
u_i {
x = 1.0,
y = 2.0,
z = 3.0,
}
out { x + y + z }
```
```
10 changes: 5 additions & 5 deletions book/src/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ ODE systems and is based on the idea that a ODE system can be specified by a set
of equations of the form:

$$
M(t) \frac{\mathrm{d}\mathbf{u}}{\mathrm{d}t} = F(\mathbf{u}, t)
M(t) \frac{\mathrm{d}\mathbf{u}}{\mathrm{d}t} = F(\mathbf{u}, \mathbf{p}, t)
$$

where \\( \mathbf{u} \\) is the vector of state variables and \\( t \\) is the time. The DSL
where \\( \mathbf{u} \\) is the vector of state variables, \\( \mathbf{p} \\) is the vector of parameters, and \\( t \\) is the time. The DSL
allows the user to specify the state vector \\( \mathbf{u} \\) and the RHS function \\( F \\).
Optionally, the user can also define the derivative of the state vector \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\)
and the mass matrix \\( M \\) as a function of \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\) (note that this function should be linear!).
Expand All @@ -18,7 +18,7 @@ scalars and vectors of the users that are required to calculate \\( F \\) and \\

## A Simple Example

To illustrate the language, consider the following simple example of a logistic growth model:
To illustrate the language, consider the following example of a logistic growth model:

$$
\frac{\mathrm{d}N}{\mathrm{d}t} = r N (1 - N/K)
Expand All @@ -28,7 +28,7 @@ where \\( N \\) is the population, \\( r \\) is the growth rate, and \\( k \\) i

To specify this model in DiffSL, we can write:

```
```diffsl
in_i { r = 1.0, k = 10.0 }
u_i {
N = 0.0
Expand All @@ -43,4 +43,4 @@ out_i {

Here, we define the input parameters for our model as a vector `in` with the growth rate `r` and the carrying capacity `k`. We then define the state vector `u_i` with the population `N` initialized to `0.0`. Next, we define the RHS function `F_i` as the logistic growth equation. Finally, we define the output vector `out_i` with the population `N`.

*For an LLM-oriented summary and index of this documentation, see [llms.txt](./llms.txt).*
*For an LLM-oriented summary and index of this documentation, see [llms.txt](./llms.txt).*
110 changes: 37 additions & 73 deletions book/src/odes.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,55 @@ $$
where \\( \mathbf{u} \\) is the vector of state variables, \\( \mathbf{u}_0 \\) is the initial condition, \\( \mathbf{p} \\) is the parameter vector, \\( F_N \\) is the model-indexed RHS function, and \\( M \\) is the mass matrix.
The DSL allows the user to specify the state vector \\( \mathbf{u} \\), parameter vector \\( \mathbf{p} \\), and RHS function \\( F_N \\).

Optionally, the user can also define the derivative of the state vector \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\) and the mass matrix \\( M \\) as a function of \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\)
(note that this function should be linear!).
The user is also free to define an arbitrary number of intermediate tensors that are required to calculate \\( F \\) and \\( M \\).

Optionally, the user can also define the derivative of the state vector \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\) and the mass matrix \\( M \\) as a function of \\( \mathrm{d}\mathbf{u}/\mathrm{d}t \\)
(note that this function should be linear!).
The user is also free to define an arbitrary number of intermediate tensors that are required to calculate \\( F \\) and \\( M \\).

## Defining the state vector

To define the state vector \\(\mathbf{u} \\), we create a special
vector tensor `u_i`. Note the particular name `u` is used to indicate that this
is the state vector.
is the state vector, and cannot be used for any othr purpose.

The values that we use for `u_i` are the initial values of the state variables
at \\( t=0 \\), so an initial condition \\( \mathbf{u}(t=0) = [x(0), y(0), z(0)] = [1, 0, 0] \\) is defined as:

```
```diffsl
u_i {
x = 1,
y = 0,
z = 0,
}
```

Since we will often use the individual elements of the state vector in the RHS function, it is useful to define them as separate variables as well.
Since we will often use the individual elements of the state vector in the RHS function, it is useful to define them using labels (`x`, `y`, `z`) so we can use them later.

The state tensor `u` must be either be a scalar or a vector. So, if we only had a single state variable, we could define it as a scalar without the index `i` as follows:

```
```diffsl
u { x = 1 }
```

We can optionally define the time derivatives of the state variables,
\\( \mathbf{\dot{u}} \\) as well:

```
```diffsl
dudt_i {
dxdt = 1,
dydt = 0,
dzdt = 0,
}
```

Here the initial values of the time derivatives are given.
In many cases any values can be given here as the time derivatives of the state variables are calculated from the RHS.
However, if there are any algebraic variables in the equations then these values can be used
used as a starting point to calculate a set of consistent initial values for the
state variables.
Here the initial values of the time derivatives are given. These values are simply placeholders and are only used
to specify the shape of each element, for example they do not need to be consistent with the RHS function `F_i` that we will define later.

Note that there is no need to define `dudt` if you do not define a mass matrix \\( M \\).

## Defining the ODE system equations

We now define the right-hand-side function \\( F \\) that we want to solve, using the
variables that we have defined earlier. We do this by defining a vector variable
variables that we have defined earlier. We do this by defining a vector (or scalar)
`F_i` that corresponds to the RHS of the equations.

For example, to define a simple system of ODEs:
Expand All @@ -80,25 +76,25 @@ $$

We write:

```
```diffsl
u_i { x = 1, y = 0 }
F_i { y, -x }
```

## Using the Ode system index `N`
## The system index `N`

**Note: hybrid ODEs using `N` and `reset` are not yet supported in the current version of diffsol or pydiffsol, please check back for updates**
**Note: hybrid ODEs using `N` and `reset` are only supported in the current version of diffsol or pydiffsol, please check back for updates**

The index `N` is used to define multiple ODE systems in the same file, indexed by the non-negative integer `N`.
This allows us to define multiple ODE systems in the same file. Combined with the stop and reset functions (see below),
This allows us to define multiple ODE systems in the same file. Combined with the stop and reset functions (see below),
this also allows us to define hybrid switching systems where we can switch between different ODE systems at different times during the simulation.

The model index `N` can be used in any of the equations, and it can be used to index into any of the tensors that we have defined.
The model index `N` can be used in any of the equations, and it can be used to index into any vectors that we have defined.

For example, we can define two ODE systems, one with exponential growth and one with exponential decay, by
defining a `g_i` vector variable that contains the growth/decay rate for each system, and then using this variable in the definition of the RHS function `F_i`:

```
```diffsl
u_i { x = 1 }
g_i { 0.1, -0.1 }
F_i { g_i[N] * x }
Expand All @@ -109,44 +105,25 @@ F_i { g_i[N] * x }
The `stop` and `reset` functions are standard tensors that can be used to stop and reset the ODE system at a given time, as long as the runtime supports this feature.

The `reset` tensor should be the same shape (i.e. a vector with the same number of elements) as the state vector `u_i`, whereas the `stop` tensor can be any length vector.
During the solve, whenever any element of the `stop` tensor is equal to zero, the ODE system will stop and, if the runtime supports hybrid models, the state of the
During the solve, whenever any element of the `stop` tensor is equal to zero, the ODE system will stop and, if the runtime supports hybrid models, the state of the
ODE system will be reset to the values defined in the `reset` tensor, and the ODE system will continue to solve from there.

The classic example of this type of hybrid model is a bouncing ball, where the ODE system is stopped when the ball hits the ground (\(x \leq 0\)), and then the state of the system is reset to a new value that corresponds to the ball bouncing back up.

```
u_i {
x = 0,
v = 10,
}
F_i {
v,
-9.81,
}
stop {
x,
}
reset {
0,
-0.8 * v,
}
```diffsl
u_i { x = 0, v = 10 }
F_i { v, -9.81 }
stop { x }
reset { 0, -0.8 * v }
```

Another example is a system that is periodically forced, for example dosing into a pharmacokinetic model, where the ODE system is stopped at regular intervals (e.g. every 24 hours), and the state of the system is reset to a new value that corresponds to the dose being administered.

```
u_i {
x = 0,
}
F_i {
-0.1 * x,
}
stop {
t - 24,
}
reset {
x + 10,
}
```diffsl
u { x = 0 }
F { -0.1 * x }
stop { t - 24 }
reset { x + 10 }
```

## Hybrid models with multiple ODE systems
Expand All @@ -155,18 +132,17 @@ The `stop` and `reset` functions can also be used to switch between different OD

For example, we can define a system that starts with exponential growth, and then switches to exponential decay after 24 hours, and then switches back to exponential growth after another 24 hours, by defining two ODE systems as before, and then using the `stop` and `reset` functions to switch between them:


```
u_i { x = 1 }
```diffsl
u { x = 1 }
g_i { 0.1, -0.1 }
F_i { g_i[N] * x }
F { g_i[N] * x }
stop { t - 48, t - 24 }
reset { 1 }
```

## Defining the mass matrix

We can also define a mass matrix \\( M \\) by defining a vector variable `M_i` which is the product of the mass matrix with the time derivative of the state vector \\( M \mathbf{\dot{u}} \\).
We can also define a mass matrix \\( M \\) by defining a vector variable `M_i` which is the product of the mass matrix with the time derivative of the state vector \\( M \mathbf{\dot{u}} \\).
This is optional, and if not defined, the mass matrix is assumed to be the identity
matrix.

Expand All @@ -186,21 +162,9 @@ $$

We write:

```diffsl
u_i { x = 1, y = 0 }
dudt_i { dxdt = 0, dydt = 1 }
M_i { dxdt, 0 }
F_i { x, y-x }
```
u_i {
x = 1,
y = 0,
}
dudt_i {
dxdt = 0,
dydt = 1,
}
M_i {
dxdt,
0,
}
F_i {
x,
y-x,
}
```
Loading
Loading