Skip to content

Commit 2ac1f7d

Browse files
shashiYingboMa
andcommitted
Merge remote-tracking branch 'origin/master' into sm/symutils3
Co-authored-by: "Yingbo Ma" <[email protected]>
2 parents ba30991 + 9ef03df commit 2ac1f7d

File tree

9 files changed

+124
-11
lines changed

9 files changed

+124
-11
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
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 = "3.20.0"
4+
version = "3.20.1"
55

66
[deps]
77
ArrayInterface = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"

src/build_function.jl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,16 @@ function add_integrator_header(ex, fargs, iip; X=gensym(:MTIIPVar))
8787
wrappedex
8888
end
8989

90+
function unflatten_long_ops(op, N=4)
91+
rule1 = @rule((+)((~~x)) => length(~~x) > N ?
92+
+(+((~~x)[1:N]...) + (+)((~~x)[N+1:end]...)) : nothing)
93+
rule2 = @rule((*)((~~x)) => length(~~x) > N ?
94+
*(*((~~x)[1:N]...) * (*)((~~x)[N+1:end]...)) : nothing)
95+
96+
op = to_symbolic(op)
97+
Rewriters.Fixpoint(Rewriters.Postwalk(Rewriters.Chain([rule1, rule2])))(op) |> to_mtk
98+
end
99+
90100
# Scalar output
91101
function _build_function(target::JuliaTarget, op, args...;
92102
conv = toexpr, expression = Val{true},
@@ -97,9 +107,10 @@ function _build_function(target::JuliaTarget, op, args...;
97107
arg_pairs = map(vars_to_pairs,zip(argnames,args))
98108
ls = reduce(vcat,first.(arg_pairs))
99109
rs = reduce(vcat,last.(arg_pairs))
100-
var_eqs = Expr(:(=), ModelingToolkit.build_expr(:tuple, ls), ModelingToolkit.build_expr(:tuple, rs))
110+
var_eqs = Expr(:(=), ModelingToolkit.build_expr(:tuple, ls), ModelingToolkit.build_expr(:tuple, unflatten_long_ops.(rs)))
101111

102112
fname = gensym(:ModelingToolkitFunction)
113+
op = unflatten_long_ops(op)
103114
out_expr = conv(op)
104115
let_expr = Expr(:let, var_eqs, Expr(:block, out_expr))
105116
bounds_block = checkbounds ? let_expr : :(@inbounds begin $let_expr end)
@@ -242,7 +253,13 @@ function _build_function(target::JuliaTarget, rhss::AbstractArray, args...;
242253
oidx = isnothing(outputidxs) ? (i -> i) : (i -> outputidxs[i])
243254
X = gensym(:MTIIPVar)
244255

245-
rhs_length = rhss isa SparseMatrixCSC ? length(rhss.nzval) : length(rhss)
256+
if rhss isa SparseMatrixCSC
257+
rhs_length = length(rhss.nzval)
258+
rhss = SparseMatrixCSC(rhss.m, rhss.m, rhss.colptr, rhss.rowval, map(unflatten_long_ops, rhss.nzval))
259+
else
260+
rhs_length = length(rhss)
261+
rhss = [unflatten_long_ops(r) for r in rhss]
262+
end
246263

247264
if parallel isa DistributedForm
248265
numworks = Distributed.nworkers()
@@ -251,6 +268,7 @@ function _build_function(target::JuliaTarget, rhss::AbstractArray, args...;
251268
finalsize = rhs_length - (numworks-1)*lens
252269
_rhss = vcat(reduce(vcat,[[getindex(reducevars[i],j) for j in 1:lens] for i in 1:numworks-1],init=Expr[]),
253270
[getindex(reducevars[end],j) for j in 1:finalsize])
271+
254272
elseif parallel isa DaggerForm
255273
computevars = [Variable(gensym(:MTComputeVar))() for i in axes(rhss,1)]
256274
reducevar = Variable(gensym(:MTReduceVar))()

src/systems/diffeqs/modelingtoolkitize.jl

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,18 @@ function modelingtoolkitize(prob::DiffEqBase.ODEProblem)
77
prob.f isa DiffEqBase.AbstractParameterizedFunction &&
88
return (prob.f.sys, prob.f.sys.states, prob.f.sys.ps)
99
@parameters t
10+
11+
if prob.p isa Tuple || prob.p isa NamedTuple
12+
p = [x for x in prob.p]
13+
else
14+
p = prob.p
15+
end
16+
1017
var(x, i) = Sym{FnType{Tuple{symtype(t)}, Number}}(nameof(Variable(:x, i)))
1118
vars = reshape([var(:x, i)(value(t)) for i in eachindex(prob.u0)],size(prob.u0))
12-
params = prob.p isa DiffEqBase.NullParameters ? [] :
13-
reshape([Variable(,i) for i in eachindex(prob.p)],size(prob.p))
19+
params = p isa DiffEqBase.NullParameters ? [] :
20+
reshape([Variable(,i) for i in eachindex(p)],size(p))
21+
1422
@derivatives D'~t
1523

1624
rhs = [D(var) for var in vars]
@@ -39,10 +47,16 @@ function modelingtoolkitize(prob::DiffEqBase.SDEProblem)
3947
prob.f isa DiffEqBase.AbstractParameterizedFunction &&
4048
return (prob.f.sys, prob.f.sys.states, prob.f.sys.ps)
4149
@parameters t
50+
if prob.p isa Tuple || prob.p isa NamedTuple
51+
p = [x for x in prob.p]
52+
else
53+
p = prob.p
54+
end
4255
var(x, i) = Sym{FnType{Tuple{symtype(t)}, Number}}(nameof(Variable(:x, i)))
4356
vars = reshape([var(:x, i)(value(t)) for i in eachindex(prob.u0)],size(prob.u0))
44-
params = prob.p isa DiffEqBase.NullParameters ? [] :
45-
reshape([Variable(,i) for i in eachindex(prob.p)],size(prob.p))
57+
params = p isa DiffEqBase.NullParameters ? [] :
58+
reshape([Variable(,i) for i in eachindex(p)],size(p))
59+
4660
@derivatives D'~t
4761

4862
rhs = [D(var) for var in vars]
@@ -68,7 +82,7 @@ function modelingtoolkitize(prob::DiffEqBase.SDEProblem)
6882
end
6983
end
7084
deqs = vcat([rhs[i] ~ lhs[i] for i in eachindex(prob.u0)]...)
71-
85+
7286
de = SDESystem(deqs,neqs,t,vec(vars),vec(params))
7387

7488
de

src/systems/diffeqs/odesystem.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,5 @@ Base.:(==)(sys1::ODESystem, sys2::ODESystem) =
145145
# NOTE: equality does not check cached Jacobian
146146

147147
function rename(sys::ODESystem,name)
148-
ODESystem(sys.eqs, sys.iv, sys.states, sys.ps, sys.tgrad, sys.jac, sys.Wfact, sys.Wfact_t, name, sys.systems)
148+
ODESystem(sys.eqs, sys.iv, sys.states, sys.ps, sys.pins, sys.observed, sys.tgrad, sys.jac, sys.Wfact, sys.Wfact_t, name, sys.systems)
149149
end

test/build_function.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,10 @@ h_julia_scalar(a, b, c, d, e, g) = a[1] + b[1] + c[1] + c[2] + c[3] + d[1] + e[1
6464
h_str_scalar = ModelingToolkit.build_function(h_scalar, [a], [b], [c1, c2, c3], [d], [e], [g])
6565
h_oop_scalar = eval(h_str_scalar)
6666
@test h_oop_scalar(inputs...) == h_julia_scalar(inputs...)
67+
68+
@variables z[1:100]
69+
@test isequal(simplify(ModelingToolkit.unflatten_long_ops(sum(z))),
70+
simplify(sum(z)))
71+
72+
@test isequal(simplify(ModelingToolkit.unflatten_long_ops(prod(z))),
73+
simplify(prod(z)))

test/components.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,35 @@ jac2 = [connected1₊lorenz1₊x 0 g zeros(1,12)
149149
zeros(Expression,7,8) ModelingToolkit.namespace_operation.(calculate_jacobian(connected2),connected2.name,:t)]
150150

151151
@test all(isequal.(calculate_jacobian(doublelevel),jac2))
152+
153+
# Try higher hierarchy
154+
155+
@parameters t σ ρ β
156+
@variables x(t) y(t) z(t)
157+
@derivatives D'~t
158+
159+
eqs = [D(x) ~ σ*(y-x),
160+
D(y) ~ x*-z)-y,
161+
D(z) ~ x*y - β*z]
162+
163+
lorenz1 = ODESystem(eqs,name=:lorenz1)
164+
lorenz2 = ODESystem(eqs,name=:lorenz2)
165+
166+
@variables a(t)
167+
@parameters γ
168+
connections = [0 ~ lorenz1.x + lorenz2.y + a*γ]
169+
170+
# Now deviate from tutorial by introducing a 2nd level of connected blocks
171+
# Other issue: How does scoping work? Is it ok to re-use components named lorenz1 and lorenz2, or will the hierarchy be flattened eventually
172+
# connected1 and 2 are pairs of Lorenz oscillators. I'd like to solve multiple pairs together.
173+
connected1 = ODESystem(connections,t,[a],[γ],systems=[lorenz1,lorenz2], name=:connected1)
174+
connected2 = ODESystem(connections,t,[a],[γ],systems=[lorenz1,lorenz2], name=:connected2)
175+
176+
connections2ndLevel = Equation[] # Pairs are not connected
177+
variables2ndLevel = [] # No extra variables
178+
parameters2ndLevel = [] # No extra parameters
179+
180+
totalSystem = ODESystem(connections2ndLevel,t,variables2ndLevel, parameters2ndLevel, systems = [connected1, connected2],
181+
name=:totalSystem)
182+
183+
connections2ndLevel = [0 ~ connected1.lorenz1.x + connected2.lorenz1.x]

test/controlsystem.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
using ModelingToolkit
22

33
@variables t x(t) v(t) u(t)
4+
@parameters p
45
@derivatives D'~t
56

67
loss = (4-x)^2 + 2v^2 + u^2
78
eqs = [
89
D(x) ~ v
9-
D(v) ~ u^3
10+
D(v) ~ p*u^3
1011
]
1112

12-
sys = ControlSystem(loss,eqs,t,[x,v],[u],[])
13+
sys = ControlSystem(loss,eqs,t,[x,v],[u],[p])
1314
dt = 0.1
1415
tspan = (0.0,1.0)
1516
runge_kutta_discretize(sys,dt,tspan)

test/modelingtoolkitize.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using OrdinaryDiffEq, ModelingToolkit
2+
const N = 32
3+
const xyd_brusselator = range(0,stop=1,length=N)
4+
brusselator_f(x, y, t) = (((x-0.3)^2 + (y-0.6)^2) <= 0.1^2) * (t >= 1.1) * 5.
5+
limit(a, N) = ModelingToolkit.ifelse(a == N+1, 1, ModelingToolkit.ifelse(a == 0, N, a))
6+
function brusselator_2d_loop(du, u, p, t)
7+
A, B, alpha, dx = p
8+
alpha = alpha/dx^2
9+
@inbounds for I in CartesianIndices((N, N))
10+
i, j = Tuple(I)
11+
x, y = xyd_brusselator[I[1]], xyd_brusselator[I[2]]
12+
ip1, im1, jp1, jm1 = limit(i+1, N), limit(i-1, N), limit(j+1, N), limit(j-1, N)
13+
du[i,j,1] = alpha*(u[im1,j,1] + u[ip1,j,1] + u[i,jp1,1] + u[i,jm1,1] - 4u[i,j,1]) +
14+
B + u[i,j,1]^2*u[i,j,2] - (A + 1)*u[i,j,1] + brusselator_f(x, y, t)
15+
du[i,j,2] = alpha*(u[im1,j,2] + u[ip1,j,2] + u[i,jp1,2] + u[i,jm1,2] - 4u[i,j,2]) +
16+
A*u[i,j,1] - u[i,j,1]^2*u[i,j,2]
17+
end
18+
end
19+
20+
# Test with tuple parameters
21+
p = (3.4, 1., 10., step(xyd_brusselator))
22+
23+
function init_brusselator_2d(xyd)
24+
N = length(xyd)
25+
u = zeros(N, N, 2)
26+
for I in CartesianIndices((N, N))
27+
x = xyd[I[1]]
28+
y = xyd[I[2]]
29+
u[I,1] = 22*(y*(1-y))^(3/2)
30+
u[I,2] = 27*(x*(1-x))^(3/2)
31+
end
32+
u
33+
end
34+
u0 = init_brusselator_2d(xyd_brusselator)
35+
36+
# Test with 3-tensor inputs
37+
prob_ode_brusselator_2d = ODEProblem(brusselator_2d_loop,
38+
u0,(0.,11.5),p)
39+
40+
modelingtoolkitize(prob_ode_brusselator_2d)

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ using SafeTestsets, Test
1919
@safetestset "ControlSystem Test" begin include("controlsystem.jl") end
2020
@safetestset "Build Targets Test" begin include("build_targets.jl") end
2121
@safetestset "Domain Test" begin include("domains.jl") end
22+
@safetestset "Modelingtoolkitize Test" begin include("modelingtoolkitize.jl") end
2223
@safetestset "Constraints Test" begin include("constraints.jl") end
2324
@safetestset "Reduction Test" begin include("reduction.jl") end
2425
@safetestset "PDE Construction Test" begin include("pde.jl") end

0 commit comments

Comments
 (0)