@@ -56,52 +56,28 @@ function liouville_transform(sys::AbstractODESystem)
56
56
ODESystem (neweqs, t, vars, parameters (sys), checks = false )
57
57
end
58
58
59
- # TODO : handle case when new iv is a variable already in the system
60
- function change_independent_variable (sys:: AbstractODESystem , iv, iv1_of_iv2, iv2_of_iv1; kwargs... )
61
- iv1 = ModelingToolkit. get_iv (sys) # old independent variable
62
- iv2 = iv # new independent variable
63
-
64
- name2 = nameof (iv2)
65
- iv2func, = @variables $ name2 (iv1)
66
-
67
- eqs = ModelingToolkit. get_eqs (sys) |> copy # don't modify original system
68
- vars = []
69
- for (i, eq) in enumerate (eqs)
70
- vars = Symbolics. get_variables (eq)
71
- for var1 in vars
72
- if Symbolics. iscall (var1) # skip e.g. constants
73
- name = nameof (operation (var1))
74
- var2, = @variables $ name (iv2func)
75
- eq = substitute (eq, var1 => var2; fold = false )
76
- end
77
- end
78
- eq = expand_derivatives (eq) # expand out with chain rule to get d(iv2)/d(iv1)
79
- eq = substitute (eq, Differential (iv1)(iv2func) => Differential (iv1)(iv2_of_iv1)) # substitute in d(iv2)/d(iv1)
80
- eq = expand_derivatives (eq)
81
- eq = substitute (eq, iv2func => iv2) # make iv2 independent
82
- eq = substitute (eq, iv1 => iv1_of_iv2) # substitute any remaining old ivars
83
- eqs[i] = eq
84
- end
85
-
86
- sys2 = typeof (sys)(eqs, iv2; name = nameof (sys), description = description (sys), kwargs... )
87
- return sys2
88
- end
89
-
90
- function change_independent_variable (sys:: AbstractODESystem , iv; kwargs... )
59
+ function change_independent_variable (sys:: AbstractODESystem , iv, eq = nothing ; verbose = false , kwargs... )
91
60
iv1 = get_iv (sys) # e.g. t
92
- iv2func = iv # e.g. a(t)
93
- iv2name = nameof (operation (unwrap (iv))) # TODO : handle namespacing?
94
- iv2, = @independent_variables $ iv2name
95
-
96
- # TODO : find iv2func in system and replace it with some dummy variable
97
- # TODO : not just to 1st, but to all orders
61
+ iv2name = nameof (iv) # TODO : handle namespacing?
62
+ iv2, = @independent_variables $ iv2name # e.g. a
63
+ iv2func, = @variables $ iv2name (iv1) # e.g. a(t)
64
+ D1 = Differential (iv1)
65
+ D2 = Differential (iv2)
98
66
99
67
div2name = Symbol (iv2name, :_t )
100
- div2, = @variables $ div2name (iv2)
68
+ div2, = @variables $ div2name (iv2) # e.g. a_t(a)
69
+
70
+ ddiv2name = Symbol (iv2name, :_tt )
71
+ ddiv2, = @variables $ ddiv2name (iv2) # e.g. a_tt(a)
101
72
102
73
eqs = ModelingToolkit. get_eqs (sys) |> copy # don't modify original system
74
+ ! isnothing (eq) && push! (eqs, eq)
103
75
vars = []
76
+ div2_div1 = nothing
104
77
for (i, eq) in enumerate (eqs)
78
+ verbose && println (" 1. " , eq)
79
+
80
+ # 1) Substitute f(t₁) => f(t₂(t₁)) in all variables
105
81
vars = Symbolics. get_variables (eq)
106
82
for var1 in vars
107
83
if Symbolics. iscall (var1) && ! isequal (var1, iv2func) # && isequal(only(arguments(var1)), iv1) # skip e.g. constants
@@ -110,17 +86,32 @@ function change_independent_variable(sys::AbstractODESystem, iv; kwargs...)
110
86
eq = substitute (eq, var1 => var2; fold = false )
111
87
end
112
88
end
89
+ verbose && println (" 2. " , eq)
90
+
91
+ # 2) Substitute in dummy variables for dⁿt₂/dt₁ⁿ
113
92
eq = expand_derivatives (eq) # expand out with chain rule to get d(iv2)/d(iv1)
114
- # eq = substitute(eq, Differential(iv1)(iv2func) => Differential(iv1)(iv2_of_iv1)) # substitute in d(iv2)/d(iv1)
115
- # eq = expand_derivatives(eq)
116
- eq = substitute (eq, Differential (iv1)(Differential (iv1)(iv2func)) => div2) # e.g. D(a(t)) => a_t(t) # TODO : more orders
117
- eq = substitute (eq, Differential (iv1)(iv2func) => div2) # e.g. D(a(t)) => a_t(t) # TODO : more orders
118
- eq = substitute (eq, iv2func => iv2) # make iv2 independent
119
- # eq = substitute(eq, iv1 => iv1_of_iv2) # substitute any remaining old ivars
93
+ verbose && println (" 3. " , eq)
94
+ eq = substitute (eq, D1 (D1 (iv2func)) => ddiv2) # order 2 # TODO : more orders
95
+ eq = substitute (eq, D1 (iv2func) => div2) # order 1; e.g. D(a(t)) => a_t(t)
96
+ eq = substitute (eq, iv2func => iv2) # order 0; make iv2 independent
97
+ verbose && println (" 4. " , eq)
98
+ verbose && println ()
99
+
120
100
eqs[i] = eq
121
- println (eq)
101
+
102
+ if isequal (eq. lhs, div2)
103
+ div2_div1 = eq. rhs
104
+ end
122
105
end
123
106
107
+ isnothing (div2_div1) && error (" No equation for $D1 ($iv2func ) was specified." )
108
+ verbose && println (" Found $div2 = $div2_div1 " )
109
+
110
+ # 3) Add equations for dummy variables
111
+ div1_div2 = 1 / div2_div1
112
+ push! (eqs, ddiv2 ~ expand_derivatives (- D2 (div1_div2) / div1_div2^ 3 )) # e.g. https://math.stackexchange.com/questions/249253/second-derivative-of-the-inverse-function # TODO : higher orders
113
+
114
+ # 4) Recreate system with new equations
124
115
sys2 = typeof (sys)(eqs, iv2; name = nameof (sys), description = description (sys), kwargs... )
125
116
return sys2
126
117
end
0 commit comments