You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ordinary differential equations describe the rate of change of some dependent variables with respect to one independent variable.
4
+
For the modeler it is often most natural to write down the equations with a particular independent variable, say time $t$.
5
+
However, in many cases there are good reasons for changing the independent variable:
6
+
7
+
1. One may want $y(x)$ as a function of $x$ instead of $(x(t), y(t))$ as a function of $t$
8
+
2. Some differential equations vary more nicely (e.g. less stiff) with respect to one independent variable than another.
9
+
3. It can reduce the number of equations that must be solved (e.g. $y(x)$ is one equation, while $(x(t), y(t))$ are two).
10
+
11
+
To manually change the independent variable of an ODE, one must rewrite all equations in terms of a new variable and transform differentials with the chain rule.
12
+
This is mechanical and error-prone.
13
+
ModelingToolkit provides the utility function [`change_independent_variable`](@ref) that automates this process.
14
+
15
+
## 1. Get one dependent variable as a function of another
16
+
17
+
Consider a projectile shot with some initial velocity in a vertical gravitational field with constant horizontal velocity.
18
+
19
+
```@example changeivar
20
+
using ModelingToolkit
21
+
using ModelingToolkit: t_nounits as t, D_nounits as D
22
+
@variables x(t) y(t)
23
+
@parameters g=9.81 v # gravitational acceleration and horizontal velocity
The derivatives are now with respect to the new independent variable $x$, which can be accessed with `M2.x`.
57
+
58
+
!!! warn
59
+
60
+
At this point `x`, `M1.x`, `M1s.x`, `M2.x`, `M2s.x` are *three* different variables.
61
+
Meanwhile `y`, `M1.y`, `M1s.y`, `M2.y` and `M2s.y` are *four* different variables.
62
+
It can be instructive to inspect these yourself to see their subtle differences.
63
+
64
+
Notice how the number of equations has also decreased from three to two, as $\mathrm{d}x/\mathrm{d}t$ has been turned into an observed equation.
65
+
It is straightforward to evolve the ODE for 10 meters and plot the resulting trajectory $y(x)$:
66
+
67
+
```@example changeivar
68
+
using OrdinaryDiffEq, Plots
69
+
prob = ODEProblem(M2s, [M2s.y => 0.0], [0.0, 10.0], [v => 8.0]) # throw 10 meters with x-velocity 8 m/s
70
+
sol = solve(prob, Tsit5())
71
+
plot(sol; idxs = M2.y) # must index by M2.y = y(x); not M1.y = y(t)!
72
+
```
73
+
74
+
!!! tip "Usage tips"
75
+
76
+
Look up the documentation of [`change_independent_variable`](@ref) for tips on how to use it.
77
+
78
+
For example, if you also need $t(x)$, you can tell it to add a differential equation for the old independent variable in terms of the new one using the [inverse function rule](https://en.wikipedia.org/wiki/Inverse_function_rule) (here $\mathrm{d}t/\mathrm{d}x = 1 / (\mathrm{d}x/\mathrm{d}t)$). If you know an analytical expression between the independent variables (here $t = x/v$), you can also pass it directly to the function to avoid the extra differential equation.
79
+
80
+
## 2. Alleviating stiffness by changing to logarithmic time
81
+
82
+
In cosmology, the [Friedmann equations](https://en.wikipedia.org/wiki/Friedmann_equations) describe the expansion of the universe.
83
+
In terms of conformal time $t$, they can be written
84
+
85
+
```@example changeivar
86
+
@variables a(t) Ω(t)
87
+
a = GlobalScope(a) # global var needed by all species
88
+
function species(w; kw...)
89
+
eqs = [D(Ω) ~ -3(1 + w) * D(a) / a * Ω]
90
+
return ODESystem(eqs, t, [Ω], []; kw...)
91
+
end
92
+
@named r = species(1 // 3) # radiation
93
+
@named m = species(0) # matter
94
+
@named Λ = species(-1) # dark energy / cosmological constant
Also notice the interesting dynamics taking place towards the end of the integration (in the early universe), which gets compressed into a very small time interval.
113
+
These ODEs would benefit from being defined with respect to a logarithmic "time" that better captures the evolution of the universe through *orders of magnitude* of time, rather than linear time.
114
+
115
+
It is therefore common to write these ODEs in terms of $b = \ln a$.
116
+
To do this, we will change the independent variable in two stages; first from $t$ to $a$, and then from $a$ to $b$.
117
+
Notice that $\mathrm{d}a/\mathrm{d}t > 0$ provided that $\Omega > 0$, and $\mathrm{d}b/\mathrm{d}a > 0$, so the transformation is well-defined since $t \leftrightarrow a \leftrightarrow b$ are one-to-one.
118
+
First, we transform from $t$ to $a$:
119
+
120
+
```@example changeivar
121
+
M2 = change_independent_variable(M1, M1.a)
122
+
@assert !ModelingToolkit.isautonomous(M2) # hide
123
+
M2 # hide
124
+
```
125
+
126
+
Unlike the original, notice that this system is *non-autonomous* because the independent variable $a$ appears explicitly in the equations!
127
+
This means that to change the independent variable from $a$ to $b$, we must provide not only the rate of change relation $db(a)/da = \exp(-b)$, but *also* the equation $a(b) = \exp(b)$ so $a$ can be eliminated in favor of $b$:
128
+
129
+
```@example changeivar
130
+
a = M2.a # get independent variable of M2
131
+
Da = Differential(a)
132
+
@variables b(a)
133
+
M3 = change_independent_variable(M2, b, [Da(b) ~ exp(-b), a ~ exp(b)])
134
+
```
135
+
136
+
We can now solve and plot the ODE in terms of $b$:
Transform the independent variable (e.g. ``t``) of the ODE system `sys` to a dependent variable `iv` (e.g. ``u(t)``).
63
+
The transformation is well-defined when the mapping between the new and old independent variables are one-to-one.
64
+
This is satisfied if one is a strictly increasing function of the other (e.g. ``du(t)/dt > 0`` or ``du(t)/dt < 0``).
65
+
66
+
Any extra equations `eqs` involving the new and old independent variables will be taken into account in the transformation.
67
+
68
+
# Keyword arguments
69
+
70
+
- `add_old_diff`: Whether to add a differential equation for the old independent variable in terms of the new one using the inverse function rule ``dt/du = 1/(du/dt)``.
71
+
- `simplify`: Whether expanded derivative expressions are simplified. This can give a tidier transformation.
72
+
- `fold`: Whether internal substitutions will evaluate numerical expressions.
73
+
74
+
# Usage before structural simplification
75
+
76
+
The variable change must take place before structural simplification.
77
+
In following calls to `structural_simplify`, consider passing `allow_symbolic = true` to avoid undesired constraint equations between between dummy variables.
78
+
79
+
# Usage with non-autonomous systems
80
+
81
+
If `sys` is non-autonomous (i.e. ``t`` appears explicitly in its equations), consider passing an algebraic equation relating the new and old independent variables (e.g. ``t = f(u(t))``).
82
+
Otherwise the transformed system can be underdetermined.
83
+
If an algebraic relation is not known, consider using `add_old_diff` instead.
84
+
85
+
# Usage with hierarchical systems
86
+
87
+
It is recommended that `iv` is a non-namespaced variable in `sys`.
88
+
This means it can belong to the top-level system or be a variable in a subsystem declared with `GlobalScope`.
89
+
90
+
# Example
91
+
92
+
Consider a free fall with constant horizontal velocity.
93
+
Physics naturally describes position as a function of time.
94
+
By changing the independent variable, it can be reformulated for vertical position as a function of horizontal position:
0 commit comments