Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create independent variables with @independent_variables #2862

Merged
merged 21 commits into from
Jul 17, 2024
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: 21 additions & 7 deletions docs/src/basics/FAQ.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ p, replace, alias = SciMLStructures.canonicalize(Tunable(), prob.p)

This error can come up after running `structural_simplify` on a system that generates dummy derivatives (i.e. variables with `ˍt`). For example, here even though all the variables are defined with initial values, the `ODEProblem` generation will throw an error that defaults are missing from the variable map.

```
```julia
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

Expand All @@ -197,13 +197,13 @@ eqs = [x1 + x2 + 1 ~ 0
2 * D(D(x1)) + D(D(x2)) + D(D(x3)) + D(x4) + 4 ~ 0]
@named sys = ODESystem(eqs, t)
sys = structural_simplify(sys)
prob = ODEProblem(sys, [], (0,1))
prob = ODEProblem(sys, [], (0, 1))
```

We can solve this problem by using the `missing_variable_defaults()` function

```
prob = ODEProblem(sys, ModelingToolkit.missing_variable_defaults(sys), (0,1))
```julia
prob = ODEProblem(sys, ModelingToolkit.missing_variable_defaults(sys), (0, 1))
```

This function provides 0 for the default values, which is a safe assumption for dummy derivatives of most models. However, the 2nd argument allows for a different default value or values to be used if needed.
Expand All @@ -221,12 +221,26 @@ julia> ModelingToolkit.missing_variable_defaults(sys, [1,2,3])
Use the `u0_constructor` keyword argument to map an array to the desired
container type. For example:

```
```julia
using ModelingToolkit, StaticArrays
using ModelingToolkit: t_nounits as t, D_nounits as D

sts = @variables x1(t)=0.0
sts = @variables x1(t) = 0.0
eqs = [D(x1) ~ 1.1 * x1]
@mtkbuild sys = ODESystem(eqs, t)
prob = ODEProblem{false}(sys, [], (0,1); u0_constructor = x->SVector(x...))
prob = ODEProblem{false}(sys, [], (0, 1); u0_constructor = x -> SVector(x...))
```

## Using a custom independent variable

When possible, we recommend `using ModelingToolkit: t_nounits as t, D_nounits as D` as the independent variable and its derivative.
However, if you want to use your own, you can do so:

```julia
using ModelingToolkit

@independent_variables x
D = Differential(x)
@variables y(x)
@named sys = ODESystem([D(y) ~ x], x)
```
28 changes: 18 additions & 10 deletions docs/src/basics/Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ Units may be assigned with the following syntax.

```@example validation
using ModelingToolkit, DynamicQuantities
@variables t [unit = u"s"] x(t) [unit = u"m"] g(t) w(t) [unit = "Hz"]
@independent_variables t [unit = u"s"]
@variables x(t) [unit = u"m"] g(t) w(t) [unit = u"Hz"]

@variables(t, [unit = u"s"], x(t), [unit = u"m"], g(t), w(t), [unit = "Hz"])
@parameters(t, [unit = u"s"])
@variables(x(t), [unit = u"m"], g(t), w(t), [unit = u"Hz"])

@parameters begin
t, [unit = u"s"]
end
@variables(begin
t, [unit = u"s"],
x(t), [unit = u"m"],
g(t),
w(t), [unit = "Hz"]
w(t), [unit = u"Hz"]
end)

# Simultaneously set default value (use plain numbers, not quantities)
Expand Down Expand Up @@ -46,10 +50,11 @@ Example usage below. Note that `ModelingToolkit` does not force unit conversions

```@example validation
using ModelingToolkit, DynamicQuantities
@independent_variables t [unit = u"ms"]
@parameters τ [unit = u"ms"]
@variables t [unit = u"ms"] E(t) [unit = u"kJ"] P(t) [unit = u"MW"]
@variables E(t) [unit = u"kJ"] P(t) [unit = u"MW"]
D = Differential(t)
eqs = eqs = [D(E) ~ P - E / τ,
eqs = [D(E) ~ P - E / τ,
0 ~ P]
ModelingToolkit.validate(eqs)
```
Expand All @@ -70,10 +75,11 @@ An example of an inconsistent system: at present, `ModelingToolkit` requires tha

```@example validation
using ModelingToolkit, DynamicQuantities
@independent_variables t [unit = u"ms"]
@parameters τ [unit = u"ms"]
@variables t [unit = u"ms"] E(t) [unit = u"J"] P(t) [unit = u"MW"]
@variables E(t) [unit = u"J"] P(t) [unit = u"MW"]
D = Differential(t)
eqs = eqs = [D(E) ~ P - E / τ,
eqs = [D(E) ~ P - E / τ,
0 ~ P]
ModelingToolkit.validate(eqs) #Returns false while displaying a warning message
```
Expand Down Expand Up @@ -115,7 +121,8 @@ In order for a function to work correctly during both validation & execution, th

```julia
using ModelingToolkit, DynamicQuantities
@variables t [unit = u"ms"] E(t) [unit = u"J"] P(t) [unit = u"MW"]
@independent_variables t [unit = u"ms"]
@variables E(t) [unit = u"J"] P(t) [unit = u"MW"]
D = Differential(t)
eqs = [D(E) ~ P - E / 1u"ms"]
ModelingToolkit.validate(eqs) #Returns false while displaying a warning message
Expand All @@ -129,8 +136,9 @@ Instead, they should be parameterized:

```@example validation3
using ModelingToolkit, DynamicQuantities
@independent_variables t [unit = u"ms"]
@parameters τ [unit = u"ms"]
@variables t [unit = u"ms"] E(t) [unit = u"kJ"] P(t) [unit = u"MW"]
@variables E(t) [unit = u"kJ"] P(t) [unit = u"MW"]
D = Differential(t)
eqs = [D(E) ~ P - E / τ]
ModelingToolkit.validate(eqs) #Returns true
Expand Down
3 changes: 2 additions & 1 deletion docs/src/tutorials/SampledData.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ H(z) = \dfrac{b_2 z^2 + b_1 z + b_0}{a_2 z^2 + a_1 z + a_0}
may thus be modeled as

```julia
@variables t y(t) [description = "Output"] u(t) [description = "Input"]
t = ModelingToolkit.t_nounits
@variables y(t) [description = "Output"] u(t) [description = "Input"]
k = ShiftIndex(Clock(t, dt))
eqs = [
a2 * y(k) + a1 * y(k - 1) + a0 * y(k - 2) ~ b2 * u(k) + b1 * u(k - 1) + b0 * u(k - 2)
Expand Down
9 changes: 5 additions & 4 deletions src/ModelingToolkit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ using .BipartiteGraphs

include("variables.jl")
include("parameters.jl")
include("independent_variables.jl")
include("constants.jl")

include("utils.jl")
Expand Down Expand Up @@ -183,13 +184,13 @@ for S in subtypes(ModelingToolkit.AbstractSystem)
end

const t_nounits = let
only(@parameters t)
only(@independent_variables t)
end
const t_unitful = let
only(@parameters t [unit = Unitful.u"s"])
only(@independent_variables t [unit = Unitful.u"s"])
end
const t = let
only(@parameters t [unit = DQ.u"s"])
only(@independent_variables t [unit = DQ.u"s"])
end

const D_nounits = Differential(t_nounits)
Expand Down Expand Up @@ -262,7 +263,7 @@ export generate_initializesystem
export alg_equations, diff_equations, has_alg_equations, has_diff_equations
export get_alg_eqs, get_diff_eqs, has_alg_eqs, has_diff_eqs

export @variables, @parameters, @constants, @brownian
export @variables, @parameters, @independent_variables, @constants, @brownian
export @named, @nonamespace, @namespace, extend, compose, complete
export debug_system

Expand Down
6 changes: 4 additions & 2 deletions src/discretedomain.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ $(FIELDS)
```jldoctest
julia> using Symbolics

julia> @variables t;
julia> t = ModelingToolkit.t_nounits

julia> Δ = Sample(t, 0.01)
(::Sample) (generic function with 2 methods)
Expand Down Expand Up @@ -166,7 +166,9 @@ The `ShiftIndex` operator allows you to index a signal and obtain a shifted disc
# Examples

```
julia> @variables t x(t);
julia> t = ModelingToolkit.t_nounits;

julia> @variables x(t);

julia> k = ShiftIndex(t, 0.1);

Expand Down
11 changes: 11 additions & 0 deletions src/independent_variables.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""
@independent_variables t₁ t₂ ...

Define one or more independent variables. For example:

@independent_variables t
@variables x(t)
"""
macro independent_variables(ts...)
:(@parameters $(ts...)) |> esc # TODO: treat independent variables separately from variables and parameters
end
4 changes: 1 addition & 3 deletions src/systems/abstractsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2237,11 +2237,10 @@ This example builds the following feedback interconnection and linearizes it fro

```julia
using ModelingToolkit
@variables t
using ModelingToolkit: t_nounits as t, D_nounits as D
function plant(; name)
@variables x(t) = 1
@variables u(t)=0 y(t)=0
D = Differential(t)
eqs = [D(x) ~ -x + u
y ~ x]
ODESystem(eqs, t; name = name)
Expand All @@ -2250,7 +2249,6 @@ end
function ref_filt(; name)
@variables x(t)=0 y(t)=0
@variables u(t)=0 [input = true]
D = Differential(t)
eqs = [D(x) ~ -2 * x + u
y ~ x]
ODESystem(eqs, t, name = name)
Expand Down
6 changes: 4 additions & 2 deletions src/systems/alias_elimination.jl
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,10 @@ Use Kahn's algorithm to topologically sort observed equations.

Example:
```julia
julia> @variables t x(t) y(t) z(t) k(t)
(t, x(t), y(t), z(t), k(t))
julia> t = ModelingToolkit.t_nounits

julia> @variables x(t) y(t) z(t) k(t)
(x(t), y(t), z(t), k(t))

julia> eqs = [
x ~ y + z
Expand Down
3 changes: 2 additions & 1 deletion src/systems/dependency_graphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ Example:

```julia
using ModelingToolkit
using ModelingToolkit: t_nounits as t
@parameters β γ κ η
@variables t S(t) I(t) R(t)
@variables S(t) I(t) R(t)

rate₁ = β * S * I
rate₂ = γ * I + t
Expand Down
3 changes: 2 additions & 1 deletion src/systems/diffeqs/basic_transformations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Example:
```julia
using ModelingToolkit, OrdinaryDiffEq, Test

@parameters t α β γ δ
@independent_variables t
@parameters α β γ δ
@variables x(t) y(t)
D = Differential(t)

Expand Down
2 changes: 1 addition & 1 deletion src/systems/diffeqs/modelingtoolkitize.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ Generate `SDESystem`, dependent variables, and parameters from an `SDEProblem`.
function modelingtoolkitize(prob::DiffEqBase.SDEProblem; kwargs...)
prob.f isa DiffEqBase.AbstractParameterizedFunction &&
return (prob.f.sys, prob.f.sys.unknowns, prob.f.sys.ps)
@parameters t
@independent_variables t
p = prob.p
has_p = !(p isa Union{DiffEqBase.NullParameters, Nothing})

Expand Down
5 changes: 3 additions & 2 deletions src/systems/diffeqs/odesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ $(FIELDS)

```julia
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

@parameters σ ρ β
@variables t x(t) y(t) z(t)
D = Differential(t)
@variables x(t) y(t) z(t)

eqs = [D(x) ~ σ*(y-x),
D(y) ~ x*(ρ-z)-y,
Expand Down Expand Up @@ -184,6 +184,7 @@ struct ODESystem <: AbstractODESystem
discrete_subsystems = nothing, solved_unknowns = nothing,
split_idxs = nothing, parent = nothing; checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(dvs, iv)
check_parameters(ps, iv)
check_equations(deqs, iv)
Expand Down
9 changes: 5 additions & 4 deletions src/systems/diffeqs/sdesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ $(FIELDS)

```julia
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

@parameters σ ρ β
@variables t x(t) y(t) z(t)
D = Differential(t)
@variables x(t) y(t) z(t)

eqs = [D(x) ~ σ*(y-x),
D(y) ~ x*(ρ-z)-y,
Expand Down Expand Up @@ -137,6 +137,7 @@ struct SDESystem <: AbstractODESystem
complete = false, index_cache = nothing, parent = nothing;
checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(dvs, iv)
check_parameters(ps, iv)
check_equations(deqs, iv)
Expand Down Expand Up @@ -320,10 +321,10 @@ experiments. Springer Science & Business Media.

```julia
using ModelingToolkit
using ModelingToolkit: t_nounits as t, D_nounits as D

@parameters α β
@variables t x(t) y(t) z(t)
D = Differential(t)
@variables x(t) y(t) z(t)

eqs = [D(x) ~ α*x]
noiseeqs = [β*x]
Expand Down
1 change: 1 addition & 0 deletions src/systems/discrete_system/discrete_system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ struct DiscreteSystem <: AbstractTimeDependentSystem
complete = false, index_cache = nothing, parent = nothing;
checks::Union{Bool, Int} = true)
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(dvs, iv)
check_parameters(ps, iv)
end
Expand Down
4 changes: 3 additions & 1 deletion src/systems/jumps/jumpsystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ $(FIELDS)

```julia
using ModelingToolkit, JumpProcesses
using ModelingToolkit: t_nounits as t

@parameters β γ
@variables t S(t) I(t) R(t)
@variables S(t) I(t) R(t)
rate₁ = β*S*I
affect₁ = [S ~ S - 1, I ~ I + 1]
rate₂ = γ*I
Expand Down Expand Up @@ -118,6 +119,7 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem
complete = false, index_cache = nothing;
checks::Union{Bool, Int} = true) where {U <: ArrayPartition}
if checks == true || (checks & CheckComponents) > 0
check_independent_variables([iv])
check_variables(unknowns, iv)
check_parameters(ps, iv)
end
Expand Down
4 changes: 2 additions & 2 deletions src/systems/pde/pdesystem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ $(FIELDS)
```julia
using ModelingToolkit

@parameters x
@variables t u(..)
@parameters x t
@variables u(..)
Dxx = Differential(x)^2
Dtt = Differential(t)^2
Dt = Differential(t)
Expand Down
13 changes: 11 additions & 2 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ const CheckAll = 1 << 0
const CheckComponents = 1 << 1
const CheckUnits = 1 << 2

function check_independent_variables(ivs)
for iv in ivs
isparameter(iv) ||
@warn "Independent variable $iv should be defined with @independent_variables $iv."
end
end

function check_parameters(ps, iv)
for p in ps
isequal(iv, p) &&
Expand Down Expand Up @@ -349,7 +356,8 @@ Return a `Set` containing all variables in `x` that appear in
Example:

```
@variables t u(t) y(t)
t = ModelingToolkit.t_nounits
@variables u(t) y(t)
D = Differential(t)
v = ModelingToolkit.vars(D(y) ~ u)
v == Set([D(y), u])
Expand Down Expand Up @@ -421,7 +429,8 @@ collect_differential_variables(sys) = collect_operator_variables(sys, Differenti
Return a `Set` with all applied operators in `x`, example:

```
@variables t u(t) y(t)
@independent_variables t
@variables u(t) y(t)
D = Differential(t)
eq = D(y) ~ u
ModelingToolkit.collect_applied_operators(eq, Differential) == Set([D(y)])
Expand Down
Loading
Loading