11# Getting Started with ModelingToolkit.jl
22
3- This is an introductory tutorial for ModelingToolkit (MTK).
4- Some examples of Ordinary Differential Equations (ODE) are used to
5- illustrate the basic user-facing functionality.
3+ This is an introductory tutorial for ModelingToolkit (MTK). We will demonstrate
4+ the basics of the package by demonstrating how to define and simulate simple
5+ Ordinary Differential Equation (ODE) systems.
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+ ```
615
716## Copy-Pastable Simplified Example
817
@@ -22,21 +31,14 @@ D = Differential(t)
2231 @variables begin
2332 x(t) # dependent variables
2433 end
25- @structural_parameters begin
26- h = 1
27- end
2834 @equations begin
29- D(x) ~ (h - x) / τ
35+ D(x) ~ (1 - x) / τ
3036 end
3137end
3238
3339using DifferentialEquations: solve
34-
35- @named fol = FOL()
36- fol = complete(fol)
37-
40+ @mtkbuild fol = FOL()
3841prob = ODEProblem(fol, [fol.x => 0.0], (0.0, 10.0), [fol.τ => 3.0])
39- # parameter `τ` can be assigned a value, but structural parameter `h` cannot'.
4042sol = solve(prob)
4143
4244using Plots
@@ -58,7 +60,7 @@ Here, ``t`` is the independent variable (time), ``x(t)`` is the (scalar) state
5860variable, `` f(t) `` is an external forcing function, and `` \tau `` is a
5961parameter.
6062In MTK, this system can be modelled as follows. For simplicity, we
61- first set the forcing function to a time-independent value `` h `` . And the
63+ first set the forcing function to a time-independent value `` 1 `` . And the
6264independent variable `` t `` is automatically added by `` @mtkmodel `` .
6365
6466``` @example ode2
@@ -74,32 +76,17 @@ D = Differential(t)
7476 @variables begin
7577 x(t) # dependent variables
7678 end
77- @structural_parameters begin
78- h = 1
79- end
8079 @equations begin
81- D(x) ~ (h - x) / τ
80+ D(x) ~ (1 - x) / τ
8281 end
8382end
8483
85- @named fol_incomplete = FOL()
86- fol = complete(fol_incomplete)
84+ @mtkbuild fol = FOL()
8785```
8886
8987Note that equations in MTK use the tilde character (` ~ ` ) as equality sign.
9088
91- ` @named ` creates an instance of ` FOL ` named as ` fol ` . Before creating an
92- ODEProblem with ` fol ` run ` complete ` . Once the system is complete, it will no
93- longer namespace its subsystems or variables. This is necessary to correctly pass
94- the intial values of states and parameters to the ODEProblem.
95-
96- ``` julia
97- julia> fol_incomplete. x
98- fol_incomplete₊x (t)
99-
100- julia> fol. x
101- x (t)
102- ```
89+ ` @mtkbuild ` creates an instance of ` FOL ` named as ` fol ` .
10390
10491After construction of the ODE, you can solve it using [ DifferentialEquations.jl] ( https://docs.sciml.ai/DiffEqDocs/stable/ ) :
10592
@@ -115,22 +102,6 @@ The initial state and the parameter values are specified using a mapping
115102from the actual symbolic elements to their values, represented as an array
116103of ` Pair ` s, which are constructed using the ` => ` operator.
117104
118- ## Non-DSL way of defining an ODESystem
119-
120- Using ` @mtkmodel ` is the preferred way of defining ODEs with MTK. However, let us
121- look at how we can define the same system without ` @mtkmodel ` . This is useful for
122- defining PDESystem etc.
123-
124- ``` @example first-mtkmodel
125- @variables t x(t) # independent and dependent variables
126- @parameters τ # parameters
127- @constants h = 1 # constants
128- D = Differential(t) # define an operator for the differentiation w.r.t. time
129-
130- # your first ODE, consisting of a single equation, indicated by ~
131- @named fol_model = ODESystem(D(x) ~ (h - x) / τ)
132- ```
133-
134105## Algebraic relations and structural simplification
135106
136107You could separate the calculation of the right-hand side, by introducing an
@@ -147,46 +118,40 @@ using ModelingToolkit
147118 x(t) # dependent variables
148119 RHS(t)
149120 end
150- @structural_parameters begin
151- h = 1
152- end
153121 begin
154122 D = Differential(t)
155123 end
156124 @equations begin
157- RHS ~ (h - x) / τ
125+ RHS ~ (1 - x) / τ
158126 D(x) ~ RHS
159127 end
160128end
161129
162- @named fol_separate = FOL()
130+ @mtkbuild fol = FOL()
163131```
164132
165- To directly solve this system, you would have to create a Differential-Algebraic
166- Equation (DAE) problem, since besides the differential equation, there is an
167- additional algebraic equation now. However, this DAE system can obviously be
168- transformed into the single ODE we used in the first example above. MTK achieves
169- this by structural simplification:
133+ You can look at the equations by using the command ` equations ` :
170134
171135``` @example ode2
172- fol_simplified = structural_simplify(complete(fol_separate))
173- equations(fol_simplified)
136+ equations(fol)
174137```
175138
139+ Notice that there is only one equation in this system, ` Differential(t)(x(t)) ~ RHS(t) ` .
140+ The other equation was removed from the system and was transformed into an ` observed `
141+ variable. Observed equations are variables which can be computed on-demand but are not
142+ necessary for the solution of the system, and thus MTK tracks it separately. One can
143+ check the observed equations via the ` observed ` function:
144+
176145``` @example ode2
177- equations(fol_simplified) == equations (fol)
146+ observed (fol)
178147```
179148
180- You can extract the equations from a system using ` equations ` (and, in the same
181- way, ` states ` and ` parameters ` ). The simplified equation is exactly the same
182- as the original one, so the simulation performance will also be the same.
183- However, there is one difference. MTK does keep track of the eliminated
184- algebraic variables as "observables" (see
185- [ Observables and Variable Elimination] ( @ref ) ).
186- That means, MTK still knows how to calculate them out of the information available
149+ For more information on this process, see [ Observables and Variable Elimination] ( @ref ) .
150+
151+ MTK still knows how to calculate them out of the information available
187152in a simulation result. The intermediate variable ` RHS ` therefore can be plotted
188- along with the state variable. Note that this has to be requested explicitly,
189- through :
153+ along with the state variable. Note that this has to be requested explicitly
154+ like as follows :
190155
191156``` @example ode2
192157prob = ODEProblem(fol_simplified,
@@ -197,16 +162,26 @@ sol = solve(prob)
197162plot(sol, vars = [fol_simplified.x, fol_simplified.RHS])
198163```
199164
200- By default, ` structural_simplify ` also replaces symbolic ` constants ` with
201- their default values. This allows additional simplifications not possible
202- when using ` parameters ` (e.g., solution of linear equations by dividing out
203- the constant's value, which cannot be done for parameters, since they may
204- be zero).
165+ ## Named Indexing of Solutions
166+
167+ Note that the indexing of the solution similarly works via the names, and so to get
168+ the time series for ` x ` , one would do:
169+
170+ ``` @example ode2
171+ sol[fol.x]
172+ ```
173+
174+ or to get the second value in the time series for ` x ` :
175+
176+ ``` @example ode2
177+ sol[fol.x,2]
178+ ```
205179
206- Note that the indexing of the solution similarly works via the names, and so
207- ` sol[x] ` gives the time-series for ` x ` , ` sol[x,2:10] ` gives the 2nd through 10th
208- values of ` x ` matching ` sol.t ` , etc. Note that this works even for variables
209- which have been eliminated, and thus ` sol[RHS] ` retrieves the values of ` RHS ` .
180+ Similarly, the time series for ` RHS ` can be retrieved using the same indexing:
181+
182+ ``` @example ode2
183+ sol[fol.RHS]
184+ ```
210185
211186## Specifying a time-variable forcing function
212187
@@ -222,9 +197,6 @@ Obviously, one could use an explicit, symbolic function of time:
222197 x(t) # dependent variables
223198 f(t)
224199 end
225- @structural_parameters begin
226- h = 1
227- end
228200 begin
229201 D = Differential(t)
230202 end
@@ -445,14 +417,9 @@ using the structural information. For more information, see the
445417
446418Here are some notes that may be helpful during your initial steps with MTK:
447419
448- - Sometimes, the symbolic engine within MTK cannot correctly identify the
449- independent variable (e.g. time) out of all variables. In such a case, you
450- usually get an error that some variable(s) is "missing from variable map". In
451- most cases, it is then sufficient to specify the independent variable as second
452- argument to ` ODESystem ` , e.g. ` ODESystem(eqs, t) ` .
453- - A completely macro-free usage of MTK is possible and is discussed in a
454- separate tutorial. This is for package developers, since the macros are only
455- essential for automatic symbolic naming for modelers.
420+ - The ` @mtkmodel ` macro is for high-level usage of MTK. However, in many cases you
421+ may need to programmatically generate ` ODESystem ` s. If that's the case, check out
422+ the [ Programmatically Generating and Scripting ODESystems Tutorial] (@ref programmatically).
456423 - Vector-valued parameters and variables are possible. A cleaner, more
457424 consistent treatment of these is still a work in progress, however. Once finished,
458425 this introductory tutorial will also cover this feature.
0 commit comments