@@ -9,21 +9,34 @@ illustrate the basic user-facing functionality.
99A much deeper tutorial with forcing functions and sparse Jacobians is below.
1010But if you want to just see some code and run, here's an example:
1111
12- ``` @example ode
12+ ``` @example first-mtkmodel
1313using ModelingToolkit
1414
15- @variables t x(t) # independent and dependent variables
16- @parameters τ # parameters
17- @constants h = 1 # constants have an assigned value
18- D = Differential(t) # define an operator for the differentiation w.r.t. time
19-
20- # your first ODE, consisting of a single equation, the equality indicated by ~
21- @named fol = ODESystem([D(x) ~ (h - x) / τ])
15+ @variables t
16+ D = Differential(t)
17+
18+ @mtkmodel FOL begin
19+ @parameters begin
20+ τ # parameters
21+ end
22+ @variables begin
23+ x(t) # dependent variables
24+ end
25+ @structural_parameters begin
26+ h = 1
27+ end
28+ @equations begin
29+ D(x) ~ (h - x) / τ
30+ end
31+ end
2232
2333using DifferentialEquations: solve
2434
25- prob = ODEProblem(fol, [x => 0.0], (0.0, 10.0), [τ => 3.0])
26- # parameter `τ` can be assigned a value, but constant `h` cannot
35+ @named fol = FOL()
36+ fol = complete(fol)
37+
38+ prob = 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'.
2740sol = solve(prob)
2841
2942using Plots
@@ -43,48 +56,110 @@ first-order lag element:
4356
4457Here, `` t `` is the independent variable (time), `` x(t) `` is the (scalar) state
4558variable, `` f(t) `` is an external forcing function, and `` \tau `` is a
46- parameter. In MTK, this system can be modelled as follows. For simplicity, we
47- first set the forcing function to a time-independent value.
59+ parameter.
60+ In 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
62+ independent variable `` t `` is automatically added by `` @mtkmodel `` .
4863
4964``` @example ode2
5065using ModelingToolkit
5166
52- @variables t x(t) # independent and dependent variables
53- @parameters τ # parameters
54- @constants h = 1 # constants
55- D = Differential(t) # define an operator for the differentiation w.r.t. time
67+ @variables t
68+ D = Differential(t)
69+
70+ @mtkmodel FOL begin
71+ @parameters begin
72+ τ # parameters
73+ end
74+ @variables begin
75+ x(t) # dependent variables
76+ end
77+ @structural_parameters begin
78+ h = 1
79+ end
80+ @equations begin
81+ D(x) ~ (h - x) / τ
82+ end
83+ end
5684
57- # your first ODE, consisting of a single equation, indicated by ~
58- @named fol_model = ODESystem(D(x) ~ (h - x) / τ )
85+ @named fol_incomplete = FOL()
86+ fol = complete(fol_incomplete )
5987```
6088
6189Note that equations in MTK use the tilde character (` ~ ` ) as equality sign.
62- Also note that the ` @named ` macro simply ensures that the symbolic name
63- matches the name in the REPL. If omitted, you can directly set the ` name ` keyword.
90+
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+ ```
64103
65104After construction of the ODE, you can solve it using [ DifferentialEquations.jl] ( https://docs.sciml.ai/DiffEqDocs/stable/ ) :
66105
67106``` @example ode2
68107using DifferentialEquations
69108using Plots
70109
71- prob = ODEProblem(fol_model , [x => 0.0], (0.0, 10.0), [τ => 3.0])
110+ prob = ODEProblem(fol , [fol. x => 0.0], (0.0, 10.0), [fol. τ => 3.0])
72111plot(solve(prob))
73112```
74113
75114The initial state and the parameter values are specified using a mapping
76115from the actual symbolic elements to their values, represented as an array
77116of ` Pair ` s, which are constructed using the ` => ` operator.
78117
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+
79134## Algebraic relations and structural simplification
80135
81136You could separate the calculation of the right-hand side, by introducing an
82137intermediate variable ` RHS ` :
83138
84139``` @example ode2
85- @variables RHS(t)
86- @named fol_separate = ODESystem([RHS ~ (h - x) / τ,
87- D(x) ~ RHS])
140+ using ModelingToolkit
141+
142+ @mtkmodel FOL begin
143+ @parameters begin
144+ τ # parameters
145+ end
146+ @variables begin
147+ x(t) # dependent variables
148+ RHS(t)
149+ end
150+ @structural_parameters begin
151+ h = 1
152+ end
153+ begin
154+ D = Differential(t)
155+ end
156+ @equations begin
157+ RHS ~ (h - x) / τ
158+ D(x) ~ RHS
159+ end
160+ end
161+
162+ @named fol_separate = FOL()
88163```
89164
90165To directly solve this system, you would have to create a Differential-Algebraic
@@ -94,12 +169,12 @@ transformed into the single ODE we used in the first example above. MTK achieves
94169this by structural simplification:
95170
96171``` @example ode2
97- fol_simplified = structural_simplify(fol_separate)
172+ fol_simplified = structural_simplify(complete( fol_separate) )
98173equations(fol_simplified)
99174```
100175
101176``` @example ode2
102- equations(fol_simplified) == equations(fol_model )
177+ equations(fol_simplified) == equations(fol )
103178```
104179
105180You can extract the equations from a system using ` equations ` (and, in the same
@@ -114,9 +189,12 @@ along with the state variable. Note that this has to be requested explicitly,
114189through:
115190
116191``` @example ode2
117- prob = ODEProblem(fol_simplified, [x => 0.0], (0.0, 10.0), [τ => 3.0])
192+ prob = ODEProblem(fol_simplified,
193+ [fol_simplified.x => 0.0],
194+ (0.0, 10.0),
195+ [fol_simplified.τ => 3.0])
118196sol = solve(prob)
119- plot(sol, vars = [x, RHS])
197+ plot(sol, vars = [fol_simplified. x, fol_simplified. RHS])
120198```
121199
122200By default, ` structural_simplify ` also replaces symbolic ` constants ` with
@@ -136,8 +214,27 @@ What if the forcing function (the “external input”) ``f(t)`` is not constant
136214Obviously, one could use an explicit, symbolic function of time:
137215
138216``` @example ode2
139- @variables f(t)
140- @named fol_variable_f = ODESystem([f ~ sin(t), D(x) ~ (f - x) / τ])
217+ @mtkmodel FOL begin
218+ @parameters begin
219+ τ # parameters
220+ end
221+ @variables begin
222+ x(t) # dependent variables
223+ f(t)
224+ end
225+ @structural_parameters begin
226+ h = 1
227+ end
228+ begin
229+ D = Differential(t)
230+ end
231+ @equations begin
232+ f ~ sin(t)
233+ D(x) ~ (f - x) / τ
234+ end
235+ end
236+
237+ @named fol_variable_f = FOL()
141238```
142239
143240But often this function might not be available in an explicit form.
@@ -154,11 +251,35 @@ value_vector = randn(10)
154251f_fun(t) = t >= 10 ? value_vector[end] : value_vector[Int(floor(t)) + 1]
155252@register_symbolic f_fun(t)
156253
157- @named fol_external_f = ODESystem([f ~ f_fun(t), D(x) ~ (f - x) / τ])
158- prob = ODEProblem(structural_simplify(fol_external_f), [x => 0.0], (0.0, 10.0), [τ => 0.75])
254+ @mtkmodel FOLExternalFunction begin
255+ @parameters begin
256+ τ # parameters
257+ end
258+ @variables begin
259+ x(t) # dependent variables
260+ f(t)
261+ end
262+ @structural_parameters begin
263+ h = 1
264+ end
265+ begin
266+ D = Differential(t)
267+ end
268+ @equations begin
269+ f ~ f_fun(t)
270+ D(x) ~ (f - x) / τ
271+ end
272+ end
273+
274+ @named fol_external_f = FOLExternalFunction()
275+ fol_external_f = complete(fol_external_f)
276+ prob = ODEProblem(structural_simplify(fol_external_f),
277+ [fol_external_f.x => 0.0],
278+ (0.0, 10.0),
279+ [fol_external_f.τ => 0.75])
159280
160281sol = solve(prob)
161- plot(sol, vars = [x, f])
282+ plot(sol, vars = [fol_external_f. x, fol_external_f. f])
162283```
163284
164285## Building component-based, hierarchical models
@@ -235,19 +356,43 @@ plot(solve(prob))
235356
236357More on this topic may be found in [ Composing Models and Building Reusable Components] (@ref acausal).
237358
238- ## Defaults
359+ ## Inital Guess
239360
240361It is often a good idea to specify reasonable values for the initial state and the
241362parameters of a model component. Then, these do not have to be explicitly specified when constructing the ` ODEProblem ` .
242363
243364``` @example ode2
244- function unitstep_fol_factory(; name)
365+ @mtkmodel UnitstepFOLFactory begin
366+ @parameters begin
367+ τ = 1.0
368+ end
369+ @variables begin
370+ x(t) = 0.0
371+ end
372+ @equations begin
373+ D(x) ~ (1 - x) / τ
374+ end
375+ end
376+ ```
377+
378+ While defining the model ` UnitstepFOLFactory ` , an initial guess of 0.0 is assigned to ` x(t) ` and 1.0 to ` τ ` .
379+ Additionaly, these initial guesses can be modified while creating instances of ` UnitstepFOLFactory ` by passing arguements.
380+
381+ ``` @example ode2
382+ @named fol = UnitstepFOLFactory(; x = 0.1)
383+ sol = ODEProblem(fol, [], (0.0, 5.0), []) |> solve
384+ ```
385+
386+ In non-DSL definitions, one can pass ` defaults ` dictionary to set the initial guess of the symbolic variables.
387+
388+ ``` @example ode3
389+ using ModelingToolkit
390+
391+ function UnitstepFOLFactory(; name)
245392 @parameters τ
246393 @variables t x(t)
247394 ODESystem(D(x) ~ (1 - x) / τ; name, defaults = Dict(x => 0.0, τ => 1.0))
248395end
249-
250- ODEProblem(unitstep_fol_factory(name = :fol), [], (0.0, 5.0), []) |> solve
251396```
252397
253398Note that the defaults can be functions of the other variables, which is then
@@ -316,6 +461,8 @@ Where to go next?
316461
317462 - Not sure how MTK relates to similar tools and packages? Read
318463 [ Comparison of ModelingToolkit vs Equation-Based and Block Modeling Languages] ( @ref ) .
464+ - For a more detailed explanation of ` @mtkmodel ` checkout
465+ [ Defining components with ` @mtkmodel ` and connectors with ` @connectors ` ] (@ref mtkmodel_connector)
319466 - Depending on what you want to do with MTK, have a look at some of the other
320467 ** Symbolic Modeling Tutorials** .
321468 - If you want to automatically convert an existing function to a symbolic
0 commit comments