Skip to content

Commit 9a7dea8

Browse files
committed
Merge branch 'master' into id-tutorial
2 parents d677739 + 52bdc81 commit 9a7dea8

34 files changed

+1469
-434
lines changed

Project.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ModelingToolkit"
22
uuid = "961ee093-0014-501f-94e3-6117800e7a78"
33
authors = ["Chris Rackauckas <[email protected]>"]
4-
version = "6.6.0"
4+
version = "7.0.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -16,13 +16,13 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1616
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1717
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1818
DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
19+
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
1920
IfElse = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
2021
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
2122
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
2223
LabelledArrays = "2ee39098-c373-598a-b85f-a56591580800"
2324
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
2425
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
25-
LightGraphs = "093fc24a-ae57-5d10-9952-331d41423f4d"
2626
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2727
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
2828
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
@@ -45,7 +45,7 @@ Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
4545

4646
[compat]
4747
AbstractTrees = "0.3"
48-
ArrayInterface = "2.8, 3.0"
48+
ArrayInterface = "3.1.39"
4949
ConstructionBase = "1"
5050
DataStructures = "0.17, 0.18"
5151
DiffEqBase = "6.54.0"
@@ -55,11 +55,11 @@ DiffRules = "0.1, 1.0"
5555
Distributions = "0.23, 0.24, 0.25"
5656
DocStringExtensions = "0.7, 0.8"
5757
DomainSets = "0.5"
58+
Graphs = "1.4"
5859
IfElse = "0.1"
59-
JuliaFormatter = "0.12, 0.13, 0.14, 0.15, 0.16, 0.17"
60+
JuliaFormatter = "0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18"
6061
LabelledArrays = "1.3"
6162
Latexify = "0.11, 0.12, 0.13, 0.14, 0.15"
62-
LightGraphs = "1.3"
6363
MacroTools = "0.5"
6464
NaNMath = "0.3"
6565
NonlinearSolve = "0.3.8"
@@ -72,8 +72,8 @@ SciMLBase = "1.3"
7272
Setfield = "0.7, 0.8"
7373
SpecialFunctions = "0.7, 0.8, 0.9, 0.10, 1.0"
7474
StaticArrays = "0.10, 0.11, 0.12, 1.0"
75-
SymbolicUtils = "0.16"
76-
Symbolics = "3.3.0"
75+
SymbolicUtils = "0.18"
76+
Symbolics = "4.0.0"
7777
UnPack = "0.1, 1.0"
7878
Unitful = "1.1"
7979
julia = "1.2"

docs/src/basics/AbstractSystem.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Optionally, a system could have:
5656

5757
- `observed(sys)`: All observed equations of the system and its subsystems.
5858
- `get_observed(sys)`: Observed equations of the current-level system.
59+
- `get_continuous_events(sys)`: `SymbolicContinuousCallback`s of the current-level system.
5960
- `get_defaults(sys)`: A `Dict` that maps variables into their default values.
6061
- `independent_variables(sys)`: The independent variables of a system.
6162
- `get_noiseeqs(sys)`: Noise equations of the current-level system.

docs/src/basics/Composition.md

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ end
3232

3333
@parameters t
3434
D = Differential(t)
35-
@named connected = compose(ODESystem([
35+
connected = compose(ODESystem([
3636
decay2.f ~ decay1.x
3737
D(decay1.f) ~ 0
38-
], t), decay1, decay2)
38+
], t; name=:connected), decay1, decay2)
3939

4040
equations(connected)
4141

@@ -250,3 +250,94 @@ strongly connected components calculated during the process of simplification
250250
as the basis for building pre-simplified nonlinear systems in the implicit
251251
solving. In summary: these problems are structurally modified, but could be
252252
more efficient and more stable.
253+
254+
## Components with discontinuous dynamics
255+
When modeling, e.g., impacts, saturations or Coulomb friction, the dynamic equations are discontinuous in either the state or one of its derivatives. This causes the solver to take very small steps around the discontinuity, and sometimes leads to early stopping due to `dt <= dt_min`. The correct way to handle such dynamics is to tell the solver about the discontinuity be means of a root-finding equation. [`ODEsystem`](@ref)s accept a keyword argument `continuous_events`
256+
```
257+
ODESystem(eqs, ...; continuous_events::Vector{Equation})
258+
ODESystem(eqs, ...; continuous_events::Pair{Vector{Equation}, Vector{Equation}})
259+
```
260+
where equations can be added that evaluate to 0 at discontinuities.
261+
262+
To model events that have an affect on the state, provide `events::Pair{Vector{Equation}, Vector{Equation}}` where the first entry in the pair is a vector of equations describing event conditions, and the second vector of equations describe the affect on the state. The affect equations must be on the form
263+
```
264+
single_state_variable ~ expression_involving_any_variables
265+
```
266+
267+
### Example: Friction
268+
The system below illustrates how this can be used to model Coulomb friction
269+
```julia
270+
using ModelingToolkit, OrdinaryDiffEq, Plots
271+
function UnitMassWithFriction(k; name)
272+
@variables t x(t)=0 v(t)=0
273+
D = Differential(t)
274+
eqs = [
275+
D(x) ~ v
276+
D(v) ~ sin(t) - k*sign(v) # f = ma, sinusoidal force acting on the mass, and Coulomb friction opposing the movement
277+
]
278+
ODESystem(eqs, t, continuous_events=[v ~ 0], name=name) # when v = 0 there is a discontinuity
279+
end
280+
@named m = UnitMassWithFriction(0.7)
281+
prob = ODEProblem(m, Pair[], (0, 10pi))
282+
sol = solve(prob, Tsit5())
283+
plot(sol)
284+
```
285+
286+
### Example: Bouncing ball
287+
In the documentation for DifferentialEquations, we have an example where a bouncing ball is simulated using callbacks which has an `affect!` on the state. We can model the same system using ModelingToolkit like this
288+
289+
```julia
290+
@variables t x(t)=1 v(t)=0
291+
D = Differential(t)
292+
293+
root_eqs = [x ~ 0] # the event happens at the ground x(t) = 0
294+
affect = [v ~ -v] # the effect is that the velocity changes sign
295+
296+
@named ball = ODESystem([
297+
D(x) ~ v
298+
D(v) ~ -9.8
299+
], t, continuous_events = root_eqs => affect) # equation => affect
300+
301+
ball = structural_simplify(ball)
302+
303+
tspan = (0.0,5.0)
304+
prob = ODEProblem(ball, Pair[], tspan)
305+
sol = solve(prob,Tsit5())
306+
@assert 0 <= minimum(sol[x]) <= 1e-10 # the ball never went through the floor but got very close
307+
plot(sol)
308+
```
309+
310+
### Test bouncing ball in 2D with walls
311+
Multiple events? No problem! This example models a bouncing ball in 2D that is enclosed by two walls at $y = \pm 1.5$.
312+
```julia
313+
@variables t x(t)=1 y(t)=0 vx(t)=0 vy(t)=2
314+
D = Differential(t)
315+
316+
continuous_events = [ # This time we have a vector of pairs
317+
[x ~ 0] => [vx ~ -vx]
318+
[y ~ -1.5, y ~ 1.5] => [vy ~ -vy]
319+
]
320+
321+
@named ball = ODESystem([
322+
D(x) ~ vx,
323+
D(y) ~ vy,
324+
D(vx) ~ -9.8-0.1vx, # gravity + some small air resistance
325+
D(vy) ~ -0.1vy,
326+
], t, continuous_events = continuous_events)
327+
328+
329+
ball = structural_simplify(ball)
330+
331+
tspan = (0.0,10.0)
332+
prob = ODEProblem(ball, Pair[], tspan)
333+
334+
sol = solve(prob,Tsit5())
335+
@assert 0 <= minimum(sol[x]) <= 1e-10 # the ball never went through the floor but got very close
336+
@assert minimum(sol[y]) > -1.5 # check wall conditions
337+
@assert maximum(sol[y]) < 1.5 # check wall conditions
338+
339+
tv = sort([LinRange(0, 10, 200); sol.t])
340+
plot(sol(tv)[y], sol(tv)[x], line_z=tv)
341+
vline!([-1.5, 1.5], l=(:black, 5), primary=false)
342+
hline!([0], l=(:black, 5), primary=false)
343+
```

docs/src/internals.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,18 @@ plotting their output, these relationships are stored and are then used to
1616
generate the `observed` equation found in the `SciMLFunction` interface, so that
1717
`sol[x]` lazily reconstructs the observed variable when necessary. In this sense,
1818
there is an equivalence between observables and the variable elimination system.
19+
20+
The procedure for variable elimination inside [`structural_simplify`](@ref) is
21+
1. [`ModelingToolkit.initialize_system_structure`](@ref).
22+
2. [`ModelingToolkit.alias_elimination`](@ref). This step moves equations into `observed(sys)`.
23+
3. [`ModelingToolkit.dae_index_lowering`](@ref) by means of [`pantelides!`](@ref) (if the system is an [`ODESystem`](@ref)).
24+
4. [`ModelingToolkit.tearing`](@ref).
25+
26+
## Preparing a system for simulation
27+
Before a simulation or optimization can be performed, the symbolic equations stored in an [`AbstractSystem`](@ref) must be converted into executable code. This step is typically occurs after the simplification explained above, and is performed when an instance of a [`AbsSciMLBase.SciMLProblem`](@ref), such as a [`ODEProblem`](@ref), is constructed.
28+
The call chain typically looks like this, with the function names in the case of an `ODESystem` indicated in parenthesis
29+
1. Problem constructor ([`ODEProblem`](@ref))
30+
2. Build an `DEFunction` ([`process_DEProblem`](@ref) -> [`ODEFunction`](@ref)
31+
3. Write actual executable code ([`generate_function`](@ref))
32+
33+
Apart from [`generate_function`](@ref), which generates the dynamics function, `ODEFunction` also builds functions for observed equations (`build_explicit_observed_function`) and jacobians (`generate_jacobian`) etc. These are all stored in the `ODEFunction`.

docs/src/mtkitize_tutorials/modelingtoolkitize_index_reduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ p = [9.8, 1]
2929
tspan = (0, 10.0)
3030
pendulum_prob = ODEProblem(pendulum_fun!, u0, tspan, p)
3131
traced_sys = modelingtoolkitize(pendulum_prob)
32-
pendulum_sys = structural_simplify(dae_index_lowering(traced_sys))
32+
pendulum_sys = structural_simplify(traced_sys)
3333
prob = ODAEProblem(pendulum_sys, Pair[], tspan)
3434
sol = solve(prob, Tsit5(),abstol=1e-8,reltol=1e-8)
3535
plot(sol, vars=states(traced_sys))

docs/src/tutorials/ode_modeling.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ again are just algebraic relations:
211211
connections = [ fol_1.f ~ 1.5,
212212
fol_2.f ~ fol_1.x ]
213213

214-
@named connected = compose(ODESystem(connections), fol_1, fol_2)
214+
connected = compose(ODESystem(connections,name=:connected), fol_1, fol_2)
215215
# Model connected with 5 equations
216216
# States (5):
217217
# fol_1₊f(t)

src/ModelingToolkit.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ import Symbolics: rename, get_variables!, _solve, hessian_sparsity,
5050
tosymbol, lower_varname, diff2term, var_from_nested_derivative,
5151
BuildTargets, JuliaTarget, StanTarget, CTarget, MATLABTarget,
5252
ParallelForm, SerialForm, MultithreadedForm, build_function,
53-
unflatten_long_ops, rhss, lhss, prettify_expr, gradient,
53+
rhss, lhss, prettify_expr, gradient,
5454
jacobian, hessian, derivative, sparsejacobian, sparsehessian,
5555
substituter, scalarize, getparent
5656

5757
import DiffEqBase: @add_kwonly
5858

59-
import LightGraphs: SimpleDiGraph, add_edge!, incidence_matrix
59+
import Graphs: SimpleDiGraph, add_edge!, incidence_matrix
6060

6161
using Requires
6262

@@ -134,6 +134,7 @@ include("systems/control/controlsystem.jl")
134134

135135
include("systems/pde/pdesystem.jl")
136136

137+
include("systems/sparsematrixclil.jl")
137138
include("systems/discrete_system/discrete_system.jl")
138139
include("systems/validation.jl")
139140
include("systems/dependency_graphs.jl")

0 commit comments

Comments
 (0)