Skip to content

Commit 5f9d51b

Browse files
Merge pull request #777 from pepijndevos/sympar
Add support for symbolic parameters
2 parents 01ce2b3 + 5dd8683 commit 5f9d51b

File tree

6 files changed

+74
-4
lines changed

6 files changed

+74
-4
lines changed

src/systems/abstractsystem.jl

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ function Base.getproperty(sys::AbstractSystem, name::Symbol)
221221
throw(error("Variable $name does not exist"))
222222
end
223223

224+
function Base.setproperty!(sys::AbstractSystem, prop::Symbol, val)
225+
if (pa = Sym{Parameter{Real}}(prop); pa in parameters(sys))
226+
sys.default_p[pa] = value(val)
227+
# comparing a Sym returns a symbolic expression
228+
elseif (st = Sym{Real}(prop); any(s->s.name==st.name, states(sys)))
229+
sys.default_u0[st] = value(val)
230+
else
231+
setfield!(sys, prop, val)
232+
end
233+
end
234+
224235
function renamespace(namespace, x)
225236
if x isa Num
226237
renamespace(namespace, value(x))
@@ -238,12 +249,12 @@ namespace_parameters(sys::AbstractSystem) = parameters(sys, parameters(sys))
238249

239250
function namespace_default_u0(sys)
240251
d_u0 = default_u0(sys)
241-
Dict(states(sys, k) => d_u0[k] for k in keys(d_u0))
252+
Dict(states(sys, k) => namespace_expr(d_u0[k], nameof(sys), independent_variable(sys)) for k in keys(d_u0))
242253
end
243254

244255
function namespace_default_p(sys)
245256
d_p = default_p(sys)
246-
Dict(parameters(sys, k) => d_p[k] for k in keys(d_p))
257+
Dict(parameters(sys, k) => namespace_expr(d_p[k], nameof(sys), independent_variable(sys)) for k in keys(d_p))
247258
end
248259

249260
function namespace_equations(sys::AbstractSystem)

src/systems/diffeqs/abstractodesystem.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,12 @@ function process_DEProblem(constructor, sys::AbstractODESystem,u0map,parammap;
266266
u0 = nothing
267267
end
268268

269+
defp = default_p(sys)
269270
if !(parammap isa DiffEqBase.NullParameters)
270271
parammap′ = lower_mapnames(parammap)
271-
p = varmap_to_vars(parammap′,ps; defaults=default_p(sys))
272+
p = varmap_to_vars(parammap′,ps; defaults=defp)
273+
elseif !isempty(defp)
274+
p = varmap_to_vars(Dict(),ps; defaults=defp)
272275
else
273276
p = ps
274277
end

src/systems/nonlinear/nonlinearsystem.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,13 @@ function process_NonlinearProblem(constructor, sys::NonlinearSystem,u0map,paramm
211211
ps = parameters(sys)
212212
u0map′ = lower_mapnames(u0map)
213213
u0 = varmap_to_vars(u0map′,dvs; defaults=default_u0(sys))
214+
defp = default_p(sys)
214215

215216
if !(parammap isa DiffEqBase.NullParameters)
216217
parammap′ = lower_mapnames(parammap)
217-
p = varmap_to_vars(parammap′,ps; defaults=default_p(sys))
218+
p = varmap_to_vars(parammap′,ps; defaults=defp)
219+
elseif !isempty(defp)
220+
p = varmap_to_vars(Dict(),ps; defaults=defp)
218221
else
219222
p = ps
220223
end

src/variables.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ applicable.
213213
function varmap_to_vars(varmap::Dict, varlist; defaults=Dict())
214214
varmap = merge(defaults, varmap) # prefers the `varmap`
215215
varmap = Dict(value(k)=>value(varmap[k]) for k in keys(varmap))
216+
# resolve symbolic parameter expressions
217+
for (p, v) in pairs(varmap)
218+
varmap[p] = fixpoint_sub(v, varmap)
219+
end
216220
T′ = eltype(values(varmap))
217221
T = Base.isconcretetype(T′) ? T′ : Base.promote_typeof(values(varmap)...)
218222
out = Vector{T}(undef, length(varlist))

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using SafeTestsets, Test
22

3+
@safetestset "Symbolic parameters test" begin include("symbolic_parameters.jl") end
34
@safetestset "Parsing Test" begin include("variable_parsing.jl") end
45
@safetestset "Differentiation Test" begin include("derivatives.jl") end
56
@safetestset "Simplify Test" begin include("simplify.jl") end

test/symbolic_parameters.jl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using ModelingToolkit
2+
using NonlinearSolve
3+
using Test
4+
5+
@variables x y z u
6+
@parameters σ ρ β
7+
8+
eqs = [0 ~ σ*(y-x),
9+
0 ~ x*-z)-y,
10+
0 ~ x*y - β*z]
11+
12+
par = [
13+
σ => 1,
14+
ρ => 0.1+σ,
15+
β => ρ*1.1
16+
]
17+
u0 = Pair{Num, Any}[
18+
x => u,
19+
y => u,
20+
z => u-0.1,
21+
]
22+
ns = NonlinearSystem(eqs, [x,y,z],[σ,ρ,β], name=:ns, default_p=par, default_u0=u0)
23+
ns.y = u*1.1
24+
ModelingToolkit.default_p(ns)
25+
resolved = ModelingToolkit.varmap_to_vars(Dict(), parameters(ns), defaults=ModelingToolkit.default_p(ns))
26+
@test resolved == [1, 0.1+1, (0.1+1)*1.1]
27+
28+
prob = NonlinearProblem(ns, [u=>1.0], Pair[])
29+
@test prob.u0 == [1.0, 1.1, 0.9]
30+
@show sol = solve(prob,NewtonRaphson())
31+
32+
@variables a
33+
@parameters b
34+
top = NonlinearSystem([0 ~ -a + ns.x+b], [a], [b], systems=[ns], name=:top)
35+
top.b = ns.σ*0.5
36+
top.ns.x = u*0.5
37+
38+
res = ModelingToolkit.varmap_to_vars(Dict(), parameters(top), defaults=ModelingToolkit.default_p(top))
39+
@test res == [0.5, 1, 0.1+1, (0.1+1)*1.1]
40+
41+
prob = NonlinearProblem(top, [states(ns, u)=>1.0, a=>1.0], Pair[])
42+
@test prob.u0 == [1.0, 0.5, 1.1, 0.9]
43+
@show sol = solve(prob,NewtonRaphson())
44+
45+
# test NullParameters+defaults
46+
prob = NonlinearProblem(top, [states(ns, u)=>1.0, a=>1.0])
47+
@test prob.u0 == [1.0, 0.5, 1.1, 0.9]
48+
@show sol = solve(prob,NewtonRaphson())

0 commit comments

Comments
 (0)