Skip to content

Commit 5b64a6b

Browse files
docs: document nameof and brownian
1 parent ebde624 commit 5b64a6b

File tree

3 files changed

+263
-0
lines changed

3 files changed

+263
-0
lines changed

demo.jl

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
macro mtkcompile(ex...)
2+
quote
3+
@mtkbuild $(ex...)
4+
end
5+
end
6+
7+
function mtkcompile(args...; kwargs...)
8+
structural_simplify(args...; kwargs...)
9+
end
10+
11+
#################################
12+
13+
using ModelingToolkit, OrdinaryDiffEq, StochasticDiffEq
14+
using ModelingToolkit: t_nounits as t, D_nounits as D
15+
16+
## ODEs
17+
18+
@parameters g
19+
@variables x(t) y(t) λ(t)
20+
eqs = [D(D(x)) ~ λ * x
21+
D(D(y)) ~ λ * y - g
22+
x^2 + y^2 ~ 1]
23+
@mtkbuild pend = System(eqs, t)
24+
prob = ODEProblem(pend, [x => -1, y => 0], (0.0, 10.0), [g => 1], guesses ==> 1])
25+
26+
sol = solve(prob, FBDF())
27+
28+
## SDEs and unified `System`
29+
30+
@variables x(t) y(t) z(t)
31+
@parameters σ ρ β
32+
@brownian a
33+
34+
eqs = [
35+
D(x) ~ σ * (y - x) + 0.1x * a,
36+
D(y) ~ x *- z) - y + 0.1y * a,
37+
D(z) ~ x * y - β * z + 0.1z * a
38+
]
39+
40+
@mtkbuild sys1 = System(eqs, t)
41+
42+
eqs = [
43+
D(x) ~ σ * (y - x),
44+
D(y) ~ x *- z) - y,
45+
D(z) ~ x * y - β * z
46+
]
47+
48+
noiseeqs = [0.1*x;
49+
0.1*y;
50+
0.1*z;;]
51+
52+
@mtkbuild sys2 = SDESystem(eqs, noiseeqs, t)
53+
54+
u0 = [
55+
x => 1.0,
56+
y => 0.0,
57+
z => 0.0]
58+
59+
p ==> 28.0,
60+
ρ => 10.0,
61+
β => 8 / 3]
62+
63+
sdeprob = SDEProblem(sys1, u0, (0.0, 10.0), p)
64+
sdesol = solve(sdeprob, ImplicitEM())
65+
66+
odeprob = ODEProblem(sys1, u0, (0.0, 10.0), p) # error!
67+
odeprob = ODEProblem(sys1, u0, (0.0, 10.0), p; check_compatibility = false)
68+
69+
@variables x y z
70+
@parameters σ ρ β
71+
72+
# Define a nonlinear system
73+
eqs = [0 ~ σ * (y - x),
74+
y ~ x *- z),
75+
β * z ~ x * y]
76+
@mtkbuild sys = System(eqs)
77+
78+
## ImplicitDiscrete Affects
79+
80+
@parameters g
81+
@variables x(t) y(t) λ(t)
82+
eqs = [D(D(x)) ~ λ * x
83+
D(D(y)) ~ λ * y - g
84+
x^2 + y^2 ~ 1]
85+
c_evt = [t ~ 5.0] => [x ~ Pre(x) + 0.1]
86+
@mtkbuild pend = System(eqs, t, continuous_events = c_evt)
87+
prob = ODEProblem(pend, [x => -1, y => 0], (0.0, 10.0), [g => 1], guesses ==> 1])
88+
89+
sol = solve(prob, FBDF())
90+
91+
## `@named` and `ParentScope`
92+
93+
function SysA(; name, var1)
94+
@variables x(t)
95+
return System([D(x) ~ var1], t; name)
96+
end
97+
function SysB(; name, var1)
98+
@variables x(t)
99+
@named subsys = SysA(; var1)
100+
return System([D(x) ~ x], t; systems = [subsys], name)
101+
end
102+
function SysC(; name)
103+
@variables x(t)
104+
@named subsys = SysB(; var1 = x)
105+
return System([D(x) ~ x], t; systems = [subsys], name)
106+
end
107+
@mtkbuild sys = SysC()

docs/src/getting_started/odes.md

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# [Building ODEs and DAEs with ModelingToolkit.jl](@id getting_started_ode)
2+
3+
This is an introductory tutorial for ModelingToolkit.jl (MTK). We will demonstrate the
4+
basics of the package by demontrating how to build systems of Ordinary Differential
5+
Equations (ODEs) and Differential-Algebraic Equations (DAEs).
6+
7+
## Installing ModelingToolkit
8+
9+
To install ModelingToolkit, use the Julia package manager. This can be done as follows:
10+
11+
```julia
12+
using Pkg
13+
Pkg.add("ModelingToolkit")
14+
```
15+
16+
## The end goal
17+
18+
TODO
19+
20+
## Basics of MTK
21+
22+
ModelingToolkit.jl is a symbolic-numeric system. This means it allows specifying a model
23+
(such as an ODE) in a similar way to how it would be written on paper. Let's start with a
24+
simple example. The system to be modeled is a first-order lag element:
25+
26+
```math
27+
\dot{x} = \frac{f(t) - x(t)}{\tau}
28+
```
29+
30+
Here, ``t`` is the independent variable (time), ``x(t)`` is the (scalar) unknown
31+
variable, ``f(t)`` is an external forcing function, and ``\tau`` is a
32+
parameter.
33+
34+
For simplicity, we will start off by setting the forcing function to a constant `1`. Every
35+
ODE has a single independent variable. MTK has a common definition for time `t` and the
36+
derivative with respect to it.
37+
38+
```@example ode2
39+
using ModelingToolkit
40+
using ModelingToolkit: t_nounits as t, D_nounits as D
41+
```
42+
43+
Next, we declare the (dependent) variables and the parameters of our model:
44+
45+
```@example ode2
46+
@variables x(t)
47+
@parameters τ
48+
```
49+
50+
Note the syntax `x(t)`. We must declare that the variable `x` is a function of the independent
51+
variable `t`. Next, we define the equations of the system:
52+
53+
```@example ode2
54+
eqs = [D(x) ~ (1 - x) / τ]
55+
```
56+
57+
Since `=` is reserved as the assignment operator, MTK uses `~` to denote equality between
58+
expressions. Now we must consolidate all of this information about our system of ODEs into
59+
ModelingToolkit's `System` type.
60+
61+
```@example ode2
62+
sys = System(eqs, t, [x], [τ]; name = :sys)
63+
```
64+
65+
The `System` constructor accepts a `Vector{Equation}` as the first argument, followed by the
66+
independent variable, a list of dependent variables, and a list of parameters. Every system
67+
must be given a name via the `name` keyword argument. Most of the time, we want to name our
68+
system the same as the variable it is assigned to. The `@named` macro helps with this:
69+
70+
```@example ode2
71+
@named sys = System(eqs, t, [x], [τ])
72+
```
73+
74+
Additionally, it may become inconvenient to specify all variables and parameters every time
75+
a system is created. MTK allows omitting these arguments, and will automatically infer them
76+
from the equations.
77+
78+
```@example ode2
79+
@named sys = System(eqs, t)
80+
```
81+
82+
Our system is not quite ready for simulation yet. First, we must use the `mtkcompile`
83+
function which transforms the system into a form that MTK can handle. For our trivial
84+
system, this does not do much.
85+
86+
```@example ode2
87+
simp_sys = mtkcompile(sys)
88+
```
89+
90+
Since building and simplifying a system is a common workflow, MTK provides the `@mtkcompile`
91+
macro for convenience.
92+
93+
```@example ode2
94+
@mtkcompile sys = System(eqs, t)
95+
```
96+
97+
We can now build an `ODEProblem` from the system. ModelingToolkit generates the necessary
98+
code for numerical ODE solvers to solve this system. We need to provide an initial
99+
value for the variable `x` and a value for the parameter `p`, as well as the time span
100+
for which to simulate the system.
101+
102+
```@example ode2
103+
prob = ODEProblem(sys, [x => 0.0, τ => 3.0], (0.0, 10.0))
104+
```
105+
106+
Here, we are saying that `x` should start at `0.0`, `τ` should be `3.0` and the system
107+
should be simulated from `t = 0.0` to `t = 10.0`. To solve the system, we must import a
108+
solver.
109+
110+
```@example ode2
111+
using OrdinaryDiffEq
112+
113+
sol = solve(prob)
114+
```
115+
116+
[OrdinaryDiffEq.jl](https://docs.sciml.ai/DiffEqDocs/stable/) contains a large number of
117+
numerical solvers. It also comes with a default solver which is used when calling
118+
`solve(prob)` and is capable of handling a large variety of systems.
119+
120+
We can obtain the timeseries of `x` by indexing the solution with the symbolic variable:
121+
122+
```@example ode2
123+
sol[x]
124+
```
125+
126+
We can even obtain timeseries of complicated expressions involving the symbolic variables in
127+
the model
128+
129+
```@example ode2
130+
sol[(1 - x) / τ]
131+
```
132+
133+
Perhaps more interesting is a plot of the solution. This can easily be achieved using Plots.jl.
134+
135+
```@example ode2
136+
using Plots
137+
138+
plot(sol)
139+
```
140+
141+
Similarly, we can plot different expressions:
142+
143+
```@example ode2
144+
plot(sol; idxs = (1 - x) / τ)
145+
```

src/systems/abstractsystem.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,18 @@ end
197197

198198
const MTKPARAMETERS_ARG = Sym{Vector{Vector}}(:___mtkparameters___)
199199

200+
"""
201+
$(TYPEDSIGNATURES)
202+
203+
Obtain the name of `sys`.
204+
"""
200205
Base.nameof(sys::AbstractSystem) = getfield(sys, :name)
206+
"""
207+
$(TYPEDSIGNATURES)
208+
209+
Obtain the description associated with `sys` if present, and an empty
210+
string otherwise.
211+
"""
201212
description(sys::AbstractSystem) = has_description(sys) ? get_description(sys) : ""
202213

203214
"""

0 commit comments

Comments
 (0)