Skip to content

Commit 956f858

Browse files
authored
Merge pull request #982 from SciML/myb/promote
Add system promotion (toodesystem)
2 parents c5ea6d7 + f2c6da1 commit 956f858

File tree

4 files changed

+58
-1
lines changed

4 files changed

+58
-1
lines changed

src/ModelingToolkit.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ include("systems/alias_elimination.jl")
136136
include("structural_transformation/StructuralTransformations.jl")
137137
@reexport using .StructuralTransformations
138138

139-
export ODESystem, ODEFunction, ODEFunctionExpr, ODEProblemExpr
139+
export ODESystem, ODEFunction, ODEFunctionExpr, ODEProblemExpr, convert_system
140140
export DAEFunctionExpr, DAEProblemExpr
141141
export SDESystem, SDEFunction, SDEFunctionExpr, SDESystemExpr
142142
export SystemStructure

src/systems/diffeqs/odesystem.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,42 @@ function collect_differential_variables(sys::ODESystem)
300300
end
301301
return diffvars
302302
end
303+
304+
# We have a stand-alone function to convert a `NonlinearSystem` or `ODESystem`
305+
# to an `ODESystem` to connect systems, and we later can reply on
306+
# `structural_simplify` to convert `ODESystem`s to `NonlinearSystem`s.
307+
"""
308+
$(TYPEDSIGNATURES)
309+
310+
Convert a `NonlinearSystem` to an `ODESystem` or converts an `ODESystem` to a
311+
new `ODESystem` with a different independent variable.
312+
"""
313+
function convert_system(::Type{<:ODESystem}, sys, t; name=nameof(sys))
314+
isempty(observed(sys)) || throw(ArgumentError("`convert_system` cannot handle reduced model (i.e. observed(sys) is non-empty)."))
315+
t = value(t)
316+
varmap = Dict()
317+
sts = states(sys)
318+
newsts = similar(sts, Any)
319+
for (i, s) in enumerate(sts)
320+
if istree(s)
321+
args = arguments(s)
322+
length(args) == 1 || throw(InvalidSystemException("Illegal state: $s. The state can have at most one argument like `x(t)`."))
323+
arg = args[1]
324+
if isequal(arg, t)
325+
newsts[i] = s
326+
continue
327+
end
328+
ns = operation(s)(t)
329+
newsts[i] = ns
330+
varmap[s] = ns
331+
else
332+
ns = indepvar2depvar(s, t)
333+
newsts[i] = ns
334+
varmap[s] = ns
335+
end
336+
end
337+
sub = Base.Fix2(substitute, varmap)
338+
neweqs = map(sub, equations(sys))
339+
defs = Dict(sub(k) => sub(v) for (k, v) in defaults(sys))
340+
return ODESystem(neweqs, t, newsts, parameters(sys); defaults=defs, name=name)
341+
end

src/utils.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,9 @@ function todict(d)
7878
end
7979

8080
_merge(d1, d2) = merge(todict(d1), todict(d2))
81+
82+
function indepvar2depvar(s::Sym, args...)
83+
T = FnType{NTuple{length(args)}, symtype(s)}
84+
ns = Sym{T}(nameof(s))(args...)
85+
@set! ns.metadata = s.metadata
86+
end

test/nonlinearsystem.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,15 @@ connected = NonlinearSystem([s ~ a + lorenz1.x
9595
lorenz1.F ~ lorenz2.u
9696
lorenz2.F ~ lorenz1.u], [s, a], [], systems=[lorenz1,lorenz2])
9797
@test_nowarn alias_elimination(connected)
98+
99+
# system promotion
100+
using OrdinaryDiffEq
101+
@variables t
102+
D = Differential(t)
103+
@named subsys = convert_system(ODESystem, lorenz1, t)
104+
@named sys = ODESystem([D(subsys.x) ~ subsys.x + subsys.x], t, systems=[subsys])
105+
sys = structural_simplify(sys)
106+
prob = ODEProblem(sys, [subsys.x => 1, subsys.z => 2.0], (0, 1.0), [subsys.σ=>1,subsys.ρ=>2,subsys.β=>3])
107+
sol = solve(prob, Rodas5())
108+
@test sol[subsys.x] + sol[subsys.y] - sol[subsys.z] sol[subsys.u]
109+
@test_throws ArgumentError convert_system(ODESystem, sys, t)

0 commit comments

Comments
 (0)