Skip to content

Commit dfc5269

Browse files
committed
Explicitly insert dummy equations into system, if requested
1 parent b8c9839 commit dfc5269

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

src/systems/diffeqs/basic_transformations.jl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ function liouville_transform(sys::AbstractODESystem; kwargs...)
5050
ODESystem(neweqs, t, vars, parameters(sys); checks = false, name = nameof(sys), kwargs...)
5151
end
5252

53-
function change_independent_variable(sys::AbstractODESystem, iv, eq = nothing; verbose = false, simplify = true, kwargs...)
53+
function change_independent_variable(sys::AbstractODESystem, iv, eq = nothing; verbose = false, simplify = true, dummies = false, kwargs...)
5454
iv1 = get_iv(sys) # e.g. t
5555
iv2name = nameof(operation(unwrap(iv))) # TODO: handle namespacing?
5656
iv2, = @independent_variables $iv2name # e.g. a
@@ -109,7 +109,15 @@ function change_independent_variable(sys::AbstractODESystem, iv, eq = nothing; v
109109
end
110110
push!(eqs, ddiv2 ~ ddiv1_ddiv2) # e.g. https://math.stackexchange.com/questions/249253/second-derivative-of-the-inverse-function # TODO: higher orders
111111

112-
# 4) Recreate system with new equations
112+
# 4) If requested, instead remove and insert dummy equations
113+
if !dummies
114+
dummyidxs = findall(eq -> isequal(eq.lhs, div2) || isequal(eq.lhs, ddiv2), eqs)
115+
dummyeqs = splice!(eqs, dummyidxs) # return and remove dummy equations
116+
dummysubs = Dict(eq.lhs => eq.rhs for eq in dummyeqs)
117+
eqs = substitute.(eqs, Ref(dummysubs)) # don't iterate over dummysubs
118+
end
119+
120+
# 5) Recreate system with new equations
113121
sys2 = typeof(sys)(eqs, iv2; name = nameof(sys), description = description(sys), kwargs...)
114122
return sys2
115123
end

test/basic_transformations.jl

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ D = Differential(t)
2525
@test sol[end, end] 1.0742818931017244
2626
end
2727

28+
@testset "Change independent variable (trivial)" begin
29+
@variables x(t) y(t)
30+
eqs1 = [D(D(x)) ~ D(x) + x, D(y) ~ 1]
31+
M1 = ODESystem(eqs1, t; name = :M) |> complete
32+
M2 = ModelingToolkit.change_independent_variable(M1, M1.y)
33+
eqs2 = substitute(equations(M2), M2.y => M1.t) # system should be equivalent when parametrized with y (since D(y) ~ 1), so substitute back ...
34+
@test eqs1[1] == only(eqs2) # ... and check that the equations are unmodified
35+
end
36+
2837
@testset "Change independent variable" begin
2938
@variables x(t) y(t) z(t) s(t)
3039
eqs = [
@@ -75,18 +84,18 @@ end
7584
@testset "Change independent variable (simple)" begin
7685
@variables x(t)
7786
Mt = ODESystem([D(x) ~ 2*x], t; name = :M) |> complete
78-
Mx = ModelingToolkit.change_independent_variable(Mt, Mt.x)
87+
Mx = ModelingToolkit.change_independent_variable(Mt, Mt.x; dummies = true)
7988
@test (@variables x x_t(x) x_tt(x); Set(equations(Mx)) == Set([x_t ~ 2x, x_tt ~ 4x]))
8089
end
8190

8291
@testset "Change independent variable (free fall)" begin
8392
@variables x(t) y(t)
8493
@parameters g v # gravitational acceleration and constant horizontal velocity
8594
Mt = ODESystem([D(D(y)) ~ -g, D(x) ~ v], t; name = :M) |> complete # gives (x, y) as function of t, ...
86-
Mx = ModelingToolkit.change_independent_variable(Mt, Mt.x) # ... but we want y as a function of x
95+
Mx = ModelingToolkit.change_independent_variable(Mt, Mt.x; dummies = false) # ... but we want y as a function of x
8796
Mx = structural_simplify(Mx; allow_symbolic = true)
8897
Dx = Differential(Mx.x)
8998
prob = ODEProblem(Mx, [Mx.y => 0.0, Dx(Mx.y) => 1.0], (0.0, 20.0), [g => 9.81, v => 10.0]) # 1 = dy/dx = (dy/dt)/(dx/dt) means equal initial horizontal and vertical velocities
9099
sol = solve(prob, Tsit5(); reltol = 1e-5)
91-
@test all(isapprox.(sol[Mx.y], sol[Mx.x - g*(Mx.x/v)^2/2]; atol = 1e-10)) # eliminate t from anal solution x(t) = v*t, y(t) = v*t - g*t^2/2
100+
@test all(isapprox.(sol[Mx.y], sol[Mx.x - g*(Mx.x/v)^2/2]; atol = 1e-10)) # compare to analytical solution (x(t) = v*t, y(t) = v*t - g*t^2/2)
92101
end

0 commit comments

Comments
 (0)