Skip to content

Commit 7ac6e4d

Browse files
committed
Merge origin/master
2 parents c31d58c + 3fbbdb0 commit 7ac6e4d

32 files changed

+783
-106
lines changed

.github/workflows/SpellCheck.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ jobs:
1010
- name: Checkout Actions Repository
1111
uses: actions/checkout@v4
1212
- name: Check spelling
13-
uses: crate-ci/typos@v1.16.25
13+
uses: crate-ci/typos@v1.17.0

Project.toml

Lines changed: 4 additions & 2 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 = ["Yingbo Ma <[email protected]>", "Chris Rackauckas <[email protected]> and contributors"]
4-
version = "8.74.1"
4+
version = "9.0.0"
55

66
[deps]
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
@@ -17,6 +17,7 @@ Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
1717
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
1818
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1919
DomainSets = "5b8099bc-c8ec-5219-889f-1d9e522a28bf"
20+
DynamicQuantities = "06fc5a27-2a28-4c7c-a15d-362465fb6821"
2021
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
2122
FunctionWrappersWrappers = "77dc65aa-8811-40c2-897b-53d922fa7daf"
2223
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
@@ -72,6 +73,7 @@ Distributed = "1"
7273
Distributions = "0.23, 0.24, 0.25"
7374
DocStringExtensions = "0.7, 0.8, 0.9"
7475
DomainSets = "0.6"
76+
DynamicQuantities = "0.8, 0.9, 0.10"
7577
ForwardDiff = "0.10.3"
7678
FunctionWrappersWrappers = "0.1"
7779
Graphs = "1.5.2"
@@ -98,7 +100,7 @@ SimpleNonlinearSolve = "0.1.0, 1"
98100
SparseArrays = "1"
99101
SpecialFunctions = "0.7, 0.8, 0.9, 0.10, 1.0, 2"
100102
StaticArrays = "0.10, 0.11, 0.12, 1.0"
101-
SymbolicIndexingInterface = "0.3"
103+
SymbolicIndexingInterface = "0.3.1"
102104
SymbolicUtils = "1.0"
103105
Symbolics = "5.7"
104106
URIs = "1"

docs/Project.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ Distributions = "0.25"
2727
Documenter = "1"
2828
ModelingToolkit = "8.33"
2929
ModelingToolkitDesigner = "1"
30-
NonlinearSolve = "0.3, 1, 2"
30+
NonlinearSolve = "0.3, 1, 2, 3"
3131
Optim = "1.7"
3232
Optimization = "3.9"
3333
OptimizationOptimJL = "0.1"
3434
OrdinaryDiffEq = "6.31"
3535
Plots = "1.36"
3636
StochasticDiffEq = "6"
37-
StructuralIdentifiability = "0.4"
37+
StructuralIdentifiability = "0.4, 0.5"
3838
SymbolicUtils = "1"
3939
Symbolics = "5"
4040
Unitful = "1.12"

ext/MTKBifurcationKitExt.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@ struct ObservableRecordFromSolution{S, T}
3434
param_end_idxs = state_end_idxs + length(parameters(nsys))
3535

3636
bif_par_idx = state_end_idxs + bif_idx
37-
# Gets the (base) substitution values for states.
37+
# Gets the (base) substitution values for states.
3838
subs_vals_states = Pair.(states(nsys), u0_vals)
39-
# Gets the (base) substitution values for parameters.
39+
# Gets the (base) substitution values for parameters.
4040
subs_vals_params = Pair.(parameters(nsys), p_vals)
41-
# Gets the (base) substitution values for observables.
41+
# Gets the (base) substitution values for observables.
4242
subs_vals_obs = [obs.lhs => substitute(obs.rhs,
4343
[subs_vals_states; subs_vals_params]) for obs in observed(nsys)]
4444
# Sometimes observables depend on other observables, hence we make a second update to this vector.
@@ -136,7 +136,7 @@ function BifurcationKit.BifurcationProblem(osys::ODESystem, args...; kwargs...)
136136
nsys = NonlinearSystem([0 ~ eq.rhs for eq in equations(osys)],
137137
states(osys),
138138
parameters(osys);
139-
name = osys.name)
139+
name = nameof(osys))
140140
return BifurcationKit.BifurcationProblem(nsys, args...; kwargs...)
141141
end
142142

format/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[deps]
2+
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"

src/ModelingToolkit.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ include("systems/pde/pdesystem.jl")
152152

153153
include("systems/sparsematrixclil.jl")
154154
include("systems/discrete_system/discrete_system.jl")
155+
include("systems/unit_check.jl")
155156
include("systems/validation.jl")
156157
include("systems/dependency_graphs.jl")
157158
include("clock.jl")

src/parameters.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ function split_parameters_by_type(ps)
100100
end
101101
tighten_types = x -> identity.(x)
102102
split_ps = tighten_types.(Base.Fix1(getindex, ps).(split_idxs))
103+
104+
if ps isa StaticArray
105+
parrs = map(x -> SArray{Tuple{size(x)...}}(x), split_ps)
106+
split_ps = SArray{Tuple{size(parrs)...}}(parrs)
107+
end
103108
if length(split_ps) == 1 #Tuple not needed, only 1 type
104109
return split_ps[1], split_idxs
105110
else

src/systems/abstractsystem.jl

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -185,75 +185,81 @@ end
185185
#Treat the result as a vector of symbols always
186186
function SymbolicIndexingInterface.is_variable(sys::AbstractSystem, sym)
187187
if unwrap(sym) isa Int # [x, 1] coerces 1 to a Num
188-
return unwrap(sym) in 1:length(unknown_states(sys))
188+
return unwrap(sym) in 1:length(variable_symbols(sys))
189189
end
190-
return any(isequal(sym), unknown_states(sys)) ||
190+
return any(isequal(sym), variable_symbols(sys)) ||
191191
hasname(sym) && is_variable(sys, getname(sym))
192192
end
193193

194194
function SymbolicIndexingInterface.is_variable(sys::AbstractSystem, sym::Symbol)
195-
return any(isequal(sym), getname.(unknown_states(sys))) ||
195+
return any(isequal(sym), getname.(variable_symbols(sys))) ||
196196
count('', string(sym)) == 1 &&
197-
count(isequal(sym), Symbol.(sys.name, :₊, getname.(unknown_states(sys)))) == 1
197+
count(isequal(sym), Symbol.(nameof(sys), :₊, getname.(variable_symbols(sys)))) ==
198+
1
198199
end
199200

200201
function SymbolicIndexingInterface.variable_index(sys::AbstractSystem, sym)
201202
if unwrap(sym) isa Int
202203
return unwrap(sym)
203204
end
204-
idx = findfirst(isequal(sym), unknown_states(sys))
205+
idx = findfirst(isequal(sym), variable_symbols(sys))
205206
if idx === nothing && hasname(sym)
206207
idx = variable_index(sys, getname(sym))
207208
end
208209
return idx
209210
end
210211

211212
function SymbolicIndexingInterface.variable_index(sys::AbstractSystem, sym::Symbol)
212-
idx = findfirst(isequal(sym), getname.(unknown_states(sys)))
213+
idx = findfirst(isequal(sym), getname.(variable_symbols(sys)))
213214
if idx !== nothing
214215
return idx
215216
elseif count('', string(sym)) == 1
216-
return findfirst(isequal(sym), Symbol.(sys.name, :₊, getname.(unknown_states(sys))))
217+
return findfirst(isequal(sym),
218+
Symbol.(nameof(sys), :₊, getname.(variable_symbols(sys))))
217219
end
218220
return nothing
219221
end
220222

223+
SymbolicIndexingInterface.variable_symbols(sys::AbstractMultivariateSystem) = sys.dvs
224+
221225
function SymbolicIndexingInterface.variable_symbols(sys::AbstractSystem)
222226
return unknown_states(sys)
223227
end
224228

225229
function SymbolicIndexingInterface.is_parameter(sys::AbstractSystem, sym)
226230
if unwrap(sym) isa Int
227-
return unwrap(sym) in 1:length(parameters(sys))
231+
return unwrap(sym) in 1:length(parameter_symbols(sys))
228232
end
229233

230-
return any(isequal(sym), parameters(sys)) ||
234+
return any(isequal(sym), parameter_symbols(sys)) ||
231235
hasname(sym) && is_parameter(sys, getname(sym))
232236
end
233237

234238
function SymbolicIndexingInterface.is_parameter(sys::AbstractSystem, sym::Symbol)
235-
return any(isequal(sym), getname.(parameters(sys))) ||
239+
return any(isequal(sym), getname.(parameter_symbols(sys))) ||
236240
count('', string(sym)) == 1 &&
237-
count(isequal(sym), Symbol.(sys.name, :₊, getname.(parameters(sys)))) == 1
241+
count(isequal(sym),
242+
Symbol.(nameof(sys), :₊, getname.(parameter_symbols(sys)))) == 1
238243
end
239244

240245
function SymbolicIndexingInterface.parameter_index(sys::AbstractSystem, sym)
241246
if unwrap(sym) isa Int
242247
return unwrap(sym)
243248
end
244-
idx = findfirst(isequal(sym), parameters(sys))
249+
idx = findfirst(isequal(sym), parameter_symbols(sys))
245250
if idx === nothing && hasname(sym)
246251
idx = parameter_index(sys, getname(sym))
247252
end
248253
return idx
249254
end
250255

251256
function SymbolicIndexingInterface.parameter_index(sys::AbstractSystem, sym::Symbol)
252-
idx = findfirst(isequal(sym), getname.(parameters(sys)))
257+
idx = findfirst(isequal(sym), getname.(parameter_symbols(sys)))
253258
if idx !== nothing
254259
return idx
255260
elseif count('', string(sym)) == 1
256-
return findfirst(isequal(sym), Symbol.(sys.name, :₊, getname.(parameters(sys))))
261+
return findfirst(isequal(sym),
262+
Symbol.(nameof(sys), :₊, getname.(parameter_symbols(sys))))
257263
end
258264
return nothing
259265
end
@@ -263,7 +269,7 @@ function SymbolicIndexingInterface.parameter_symbols(sys::AbstractSystem)
263269
end
264270

265271
function SymbolicIndexingInterface.is_independent_variable(sys::AbstractSystem, sym)
266-
return any(isequal(sym), independent_variables(sys))
272+
return any(isequal(sym), independent_variable_symbols(sys))
267273
end
268274

269275
function SymbolicIndexingInterface.is_independent_variable(sys::AbstractSystem, sym::Symbol)
@@ -284,6 +290,20 @@ SymbolicIndexingInterface.is_time_dependent(::AbstractTimeIndependentSystem) = f
284290

285291
SymbolicIndexingInterface.constant_structure(::AbstractSystem) = true
286292

293+
function SymbolicIndexingInterface.all_variable_symbols(sys::AbstractSystem)
294+
syms = variable_symbols(sys)
295+
obs = getproperty.(observed(sys), :lhs)
296+
return isempty(obs) ? syms : vcat(syms, obs)
297+
end
298+
299+
function SymbolicIndexingInterface.all_symbols(sys::AbstractSystem)
300+
syms = all_variable_symbols(sys)
301+
for other in (parameter_symbols(sys), independent_variable_symbols(sys))
302+
isempty(other) || (syms = vcat(syms, other))
303+
end
304+
return syms
305+
end
306+
287307
iscomplete(sys::AbstractSystem) = isdefined(sys, :complete) && getfield(sys, :complete)
288308

289309
"""
@@ -303,6 +323,7 @@ for prop in [:eqs
303323
:states
304324
:ps
305325
:tspan
326+
:name
306327
:var_to_name
307328
:ctrls
308329
:defaults
@@ -639,7 +660,7 @@ function states(sys::AbstractSystem)
639660
end
640661
isempty(nonunique_states) && return nonunique_states
641662
# `Vector{Any}` is incompatible with the `SymbolicIndexingInterface`, which uses
642-
# `elsymtype = symbolic_type(eltype(_arg))`
663+
# `elsymtype = symbolic_type(eltype(_arg))`
643664
# which inappropriately returns `NotSymbolic()`
644665
if nonunique_states isa Vector{Any}
645666
nonunique_states = _nonum.(nonunique_states)
@@ -650,6 +671,12 @@ end
650671

651672
function parameters(sys::AbstractSystem)
652673
ps = get_ps(sys)
674+
if ps == SciMLBase.NullParameters()
675+
return []
676+
end
677+
if eltype(ps) <: Pair
678+
ps = first.(ps)
679+
end
653680
systems = get_systems(sys)
654681
unique(isempty(systems) ? ps : [ps; reduce(vcat, namespace_parameters.(systems))])
655682
end

src/systems/diffeqs/abstractodesystem.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,13 @@ function DiffEqBase.ODEProblem(sys::AbstractODESystem, args...; kwargs...)
912912
ODEProblem{true}(sys, args...; kwargs...)
913913
end
914914

915+
function DiffEqBase.ODEProblem(sys::AbstractODESystem,
916+
u0map::StaticArray,
917+
args...;
918+
kwargs...)
919+
ODEProblem{false, SciMLBase.FullSpecialize}(sys, u0map, args...; kwargs...)
920+
end
921+
915922
function DiffEqBase.ODEProblem{true}(sys::AbstractODESystem, args...; kwargs...)
916923
ODEProblem{true, SciMLBase.AutoSpecialize}(sys, args...; kwargs...)
917924
end

src/systems/diffeqs/odesystem.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,8 @@ struct ODESystem <: AbstractODESystem
163163
check_equations(equations(cevents), iv)
164164
end
165165
if checks == true || (checks & CheckUnits) > 0
166-
all_dimensionless([dvs; ps; iv]) || check_units(deqs)
166+
u = __get_unit_type(dvs, ps, iv)
167+
check_units(u, deqs)
167168
end
168169
new(tag, deqs, iv, dvs, ps, tspan, var_to_name, ctrls, observed, tgrad, jac,
169170
ctrl_jac, Wfact, Wfact_t, name, systems, defaults, torn_matching,

src/systems/diffeqs/sdesystem.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ struct SDESystem <: AbstractODESystem
134134
check_equations(equations(cevents), iv)
135135
end
136136
if checks == true || (checks & CheckUnits) > 0
137-
all_dimensionless([dvs; ps; iv]) || check_units(deqs, neqs)
137+
u = __get_unit_type(dvs, ps, iv)
138+
check_units(u, deqs, neqs)
138139
end
139140
new(tag, deqs, neqs, iv, dvs, ps, tspan, var_to_name, ctrls, observed, tgrad, jac,
140141
ctrl_jac,

src/systems/discrete_system/discrete_system.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ struct DiscreteSystem <: AbstractTimeDependentSystem
103103
check_parameters(ps, iv)
104104
end
105105
if checks == true || (checks & CheckUnits) > 0
106-
all_dimensionless([dvs; ps; iv; ctrls]) || check_units(discreteEqs)
106+
u = __get_unit_type(dvs, ps, iv, ctrls)
107+
check_units(u, discreteEqs)
107108
end
108109
new(tag, discreteEqs, iv, dvs, ps, tspan, var_to_name, ctrls, observed, name,
109110
systems,

src/systems/jumps/jumpsystem.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ struct JumpSystem{U <: ArrayPartition} <: AbstractTimeDependentSystem
112112
check_parameters(ps, iv)
113113
end
114114
if checks == true || (checks & CheckUnits) > 0
115-
all_dimensionless([states; ps; iv]) || check_units(ap, iv)
115+
u = __get_unit_type(states, ps, iv)
116+
check_units(u, ap, iv)
116117
end
117118
new{U}(tag, ap, iv, states, ps, var_to_name, observed, name, systems, defaults,
118119
connector_type, devents, metadata, gui_metadata, complete)

src/systems/model_parsing.jl

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,10 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs;
178178
(var, def)
179179
end
180180
Expr(:ref, a, b...) => begin
181+
indices = map(i -> UnitRange(i.args[2], i.args[end]), b)
181182
parse_variable_def!(dict, mod, a, varclass, kwargs;
182-
def, indices = [eval.(b)...])
183+
def, indices)
183184
end
184-
#= Expr(:if, condition, a) => begin
185-
var, def = [], []
186-
for var_def in a.args
187-
parse_variable_def!(dict, mod, var_def, varclass, kwargs)
188-
end
189-
end =#
190185
_ => error("$arg cannot be parsed")
191186
end
192187
end
@@ -301,7 +296,7 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps,
301296
parse_equations!(exprs, eqs, dict, body)
302297
elseif mname == Symbol("@icon")
303298
isassigned(icon) && error("This model has more than one icon.")
304-
parse_icon!(icon, dict, body)
299+
parse_icon!(body, dict, icon, mod)
305300
else
306301
error("$mname is not handled.")
307302
end
@@ -614,7 +609,7 @@ function parse_equations!(exprs, eqs, dict, body)
614609
end
615610
end
616611

617-
function parse_icon!(icon, dict, body::String)
612+
function parse_icon!(body::String, dict, icon, mod)
618613
icon_dir = get(ENV, "MTK_ICONS_DIR", joinpath(DEPOT_PATH[1], "mtk_icons"))
619614
dict[:icon] = icon[] = if isfile(body)
620615
URI("file:///" * abspath(body))
@@ -633,8 +628,8 @@ function parse_icon!(icon, dict, body::String)
633628
end
634629
end
635630

636-
function parse_icon!(icon, dict, body::Expr)
637-
parse_icon!(icon, dict, eval(body))
631+
function parse_icon!(body::Symbol, dict, icon, mod)
632+
parse_icon!(getfield(mod, body), dict, icon, mod)
638633
end
639634

640635
### Parsing Components:

src/systems/nonlinear/nonlinearsystem.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ struct NonlinearSystem <: AbstractTimeIndependentSystem
8888
tearing_state = nothing, substitutions = nothing,
8989
complete = false, parent = nothing; checks::Union{Bool, Int} = true)
9090
if checks == true || (checks & CheckUnits) > 0
91-
all_dimensionless([states; ps]) || check_units(eqs)
91+
u = __get_unit_type(states, ps)
92+
check_units(u, eqs)
9293
end
9394
new(tag, eqs, states, ps, var_to_name, observed, jac, name, systems, defaults,
9495
connector_type, metadata, gui_metadata, tearing_state, substitutions, complete,

src/systems/optimization/constraints_system.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ struct ConstraintsSystem <: AbstractTimeIndependentSystem
7777
tearing_state = nothing, substitutions = nothing;
7878
checks::Union{Bool, Int} = true)
7979
if checks == true || (checks & CheckUnits) > 0
80-
all_dimensionless([states; ps]) || check_units(constraints)
80+
u = __get_unit_type(states, ps)
81+
check_units(u, constraints)
8182
end
8283
new(tag, constraints, states, ps, var_to_name, observed, jac, name, systems,
8384
defaults,

src/systems/optimization/optimizationsystem.jl

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,10 @@ struct OptimizationSystem <: AbstractOptimizationSystem
6666
gui_metadata = nothing, complete = false, parent = nothing;
6767
checks::Union{Bool, Int} = true)
6868
if checks == true || (checks & CheckUnits) > 0
69-
unwrap(op) isa Symbolic && check_units(op)
70-
check_units(observed)
71-
all_dimensionless([states; ps]) || check_units(constraints)
69+
u = __get_unit_type(states, ps)
70+
unwrap(op) isa Symbolic && check_units(u, op)
71+
check_units(u, observed)
72+
check_units(u, constraints)
7273
end
7374
new(tag, op, states, ps, var_to_name, observed,
7475
constraints, name, systems, defaults, metadata, gui_metadata, complete,

0 commit comments

Comments
 (0)