Skip to content

Change independent variable of ODE systems #3437

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
acec3cb
Change independent variable of simple 1st order system
hersle Feb 23, 2025
3600b0d
Change independent variable of 2nd-order systems
hersle Feb 23, 2025
acd0fab
Change independent variable to a dependent one
hersle Mar 1, 2025
865ef02
Merge functions for changing independent variable into one
hersle Mar 1, 2025
af3ae69
Fix broken Liouville transform test/documentation
hersle Mar 2, 2025
cbceec4
Specify new independent variable as a dependent variable in the old s…
hersle Mar 2, 2025
75fe0f0
Optionally simplify dummy derivative expressions when changing indepe…
hersle Mar 2, 2025
b8c9839
Improve change of independent variable tests
hersle Mar 2, 2025
dfc5269
Explicitly insert dummy equations into system, if requested
hersle Mar 2, 2025
ae9c174
Add and test errors when changing independent variable
hersle Mar 2, 2025
00b2711
Export and document change_independent_variable
hersle Mar 2, 2025
ee21223
Handle autonomous systems and more fields
hersle Mar 3, 2025
9444d93
Add tutorial for changing independent variable
hersle Mar 3, 2025
9831886
Reorder things and make universal function that transforms all ODESys…
hersle Mar 3, 2025
1ac7c7d
Clean up independent variable change implementation
hersle Mar 4, 2025
34a6a4e
Actually run basic transformations test
hersle Mar 5, 2025
636ad04
Change independent variable of hierarchical systems
hersle Mar 5, 2025
2afacb5
Forbid DDEs for now
hersle Mar 6, 2025
2d5aa12
Use vars(ex; op = Nothing) instead of get_variables(ex)
hersle Mar 6, 2025
5780d91
Print detected transformation equations when there is not exactly one
hersle Mar 6, 2025
5ca058d
Use default_toterm (with special underscore) for dummies
hersle Mar 6, 2025
2397d9a
Change independent variable of incomplete systems
hersle Mar 6, 2025
a277854
Warn user about subtle differences between variables after change of …
hersle Mar 6, 2025
aa29107
Update change_independent_variable docstring
hersle Mar 6, 2025
ea5a003
Explicitly test that c*D(x) ~ something fails, but add TODO to fix it
hersle Mar 6, 2025
0e41e04
Prepare test for array variables (until expand_derivatives bug is fixed)
hersle Mar 7, 2025
d660269
Test change_independent_variable with registered functions and callab…
hersle Mar 7, 2025
10793d2
Optionally add differential equation for old independent variable
hersle Mar 7, 2025
2b0998b
Rewrite change_independent_variable to handle any derivative order an…
hersle Mar 8, 2025
f2a1a5a
Test 3rd order nonlinear system
hersle Mar 9, 2025
aaae59d
Clean up and format
hersle Mar 9, 2025
7f821e2
Use t_nounits, D_nounits
hersle Mar 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Change independent variable of simple 1st order system
  • Loading branch information
hersle committed Mar 5, 2025
commit acec3cb7e2ae3037d239a4e09ef57d73e6a72559
31 changes: 31 additions & 0 deletions src/systems/diffeqs/basic_transformations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,34 @@ function liouville_transform(sys::AbstractODESystem)
vars = [unknowns(sys); trJ]
ODESystem(neweqs, t, vars, parameters(sys), checks = false)
end

# TODO: handle case when new iv is a variable already in the system
function change_independent_variable(sys::AbstractODESystem, iv, iv1_of_iv2; kwargs...)
iv1 = ModelingToolkit.get_iv(sys) # old independent variable
iv2 = iv # new independent variable

name2 = nameof(iv2)
iv2func, = @variables $name2(iv1)

eqs = ModelingToolkit.get_eqs(sys) |> copy # don't modify original system
vars = []
for (i, eq) in enumerate(eqs)
vars = Symbolics.get_variables(eq)
for var1 in vars
if Symbolics.iscall(var1) # skip e.g. constants
name = nameof(operation(var1))
var2, = @variables $name(iv2func)
eq = substitute(eq, var1 => var2; fold = false)
end
end
eq = expand_derivatives(eq) # expand out with chain rule to get d(iv2)/d(iv1)
div1_div2 = Differential(iv2)(iv1_of_iv2) |> expand_derivatives
div2_div1 = 1 / div1_div2
eq = substitute(eq, Differential(iv1)(iv2func) => div2_div1) # substitute in d(iv1)/d(iv2)
eq = substitute(eq, iv2func => iv2) # make iv2 independent
eqs[i] = eq
end

sys2 = typeof(sys)(eqs, iv2; name = nameof(sys), description = description(sys), kwargs...)
return sys2
end
25 changes: 25 additions & 0 deletions test/basic_transformations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,28 @@ u0 = [x => 1.0,
prob = ODEProblem(sys2, u0, tspan, p, jac = true)
sol = solve(prob, Tsit5())
@test sol[end, end] ≈ 1.0742818931017244

@testset "Change independent variable" begin
# Autonomous 1st order (t doesn't appear in the equations)
@independent_variables t
@variables x(t) y(t) z(t)
eqs = [
D(x) ~ y
D(y) ~ 2*D(x)
z ~ x + D(y)
]
@named sys1 = ODESystem(eqs, t)

@independent_variables s
@named sys2 = ModelingToolkit.change_independent_variable(sys1, s, s^2)

sys1 = structural_simplify(sys1)
sys2 = structural_simplify(sys2)
prob1 = ODEProblem(sys1, unknowns(sys1) .=> 1.0, (0.0, 1.0))
prob2 = ODEProblem(sys2, unknowns(sys2) .=> 1.0, (0.0, 1.0))
sol1 = solve(prob1, Tsit5(); reltol = 1e-10, abstol = 1e-10)
sol2 = solve(prob2, Tsit5(); reltol = 1e-10, abstol = 1e-10)
ts = range(0.0, 1.0, length = 50)
ss = .√(ts)
@test isapprox(sol1(ts), sol2(ss); atol = 1e-8)
end