Skip to content

Commit 04ed74f

Browse files
Merge pull request #147 from SebastianM-C/phys-update
Classical Physics tutorial improvements
2 parents fa5d0e0 + fa75fe2 commit 04ed74f

19 files changed

+943
-174
lines changed

html/models/01-classical_physics.html

+165-100
Large diffs are not rendered by default.

markdown/models/01-classical_physics.md

+589
Large diffs are not rendered by default.
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

notebook/models/01-classical_physics.ipynb

+32-16
Large diffs are not rendered by default.

pdf/models/01-classical_physics.pdf

50.3 KB
Binary file not shown.

script/models/01-classical_physics.jl

+45-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,35 @@ plot(sol,linewidth=2,title ="Carbon-14 half-life", xaxis = "Time in thousands of
2121
plot!(sol.t, t->exp(-C₁*t),lw=3,ls=:dash,label="Analytical Solution")
2222

2323

24+
# Simple Harmonic Oscillator Problem
25+
using OrdinaryDiffEq, Plots
26+
27+
#Parameters
28+
ω = 1
29+
30+
#Initial Conditions
31+
x₀ = [0.0]
32+
dx₀ =/2]
33+
tspan = (0.0, 2π)
34+
35+
ϕ = atan((dx₀[1]/ω)/x₀[1])
36+
A = (x₀[1]^2 + dx₀[1]^2)
37+
38+
#Define the problem
39+
function harmonicoscillator(ddu,du,u,ω,t)
40+
ddu .= -ω^2 * u
41+
end
42+
43+
#Pass to solvers
44+
prob = SecondOrderODEProblem(harmonicoscillator, dx₀, x₀, tspan, ω)
45+
sol = solve(prob, DPRKN6())
46+
47+
#Plot
48+
plot(sol, vars=[2,1], linewidth=2, title ="Simple Harmonic Oscillator", xaxis = "Time", yaxis = "Elongation", label = ["x" "dx"])
49+
plot!(t->A*cos*t-ϕ), lw=3, ls=:dash, label="Analytical Solution x")
50+
plot!(t->-A*ω*sin*t-ϕ), lw=3, ls=:dash, label="Analytical Solution dx")
51+
52+
2453
# Simple Pendulum Problem
2554
using OrdinaryDiffEq, Plots
2655

@@ -34,18 +63,18 @@ tspan = (0.0,6.3)
3463

3564
#Define the problem
3665
function simplependulum(du,u,p,t)
37-
θ = u[1]
66+
θ = u[1]
3867
= u[2]
3968
du[1] =
4069
du[2] = -(g/L)*sin(θ)
4170
end
4271

4372
#Pass to solvers
44-
prob = ODEProblem(simplependulum,u₀, tspan)
73+
prob = ODEProblem(simplependulum, u₀, tspan)
4574
sol = solve(prob,Tsit5())
4675

4776
#Plot
48-
plot(sol,linewidth=2,title ="Simple Pendulum Problem", xaxis = "Time", yaxis = "Height", label = ["Theta","dTheta"])
77+
plot(sol,linewidth=2,title ="Simple Pendulum Problem", xaxis = "Time", yaxis = "Height", label = ["\\theta" "d\\theta"])
4978

5079

5180
p = plot(sol,vars = (1,2), xlims = (-9,9), title = "Phase Space Plot", xaxis = "Velocity", yaxis = "Position", leg=false)
@@ -104,7 +133,7 @@ plot(ps...)
104133
#Constants and setup
105134
using OrdinaryDiffEq
106135
initial2 = [0.01, 0.005, 0.01, 0.01]
107-
tspan2 = (0.,200.)
136+
tspan2 = (0.,500.)
108137

109138
#Define the problem
110139
function double_pendulum_hamiltonian(udot,u,p,t)
@@ -127,20 +156,21 @@ cb = ContinuousCallback(condition,affect!,nothing,
127156

128157
# Construct Problem
129158
poincare = ODEProblem(double_pendulum_hamiltonian, initial2, tspan2)
130-
sol2 = solve(poincare, Vern9(), save_everystep = false, callback=cb, abstol=1e-9)
159+
sol2 = solve(poincare, Vern9(), save_everystep = false, save_start=false, save_end=false, callback=cb, abstol=1e-16, reltol=1e-16,)
131160

132161
function poincare_map(prob, u₀, p; callback=cb)
133-
_prob = ODEProblem(prob.f,[0.01, 0.01, 0.01, u₀],prob.tspan)
134-
sol = solve(_prob, Vern9(), save_everystep = false, callback=cb, abstol=1e-9)
135-
scatter!(p, sol, vars=(3,4), markersize = 2)
162+
_prob = ODEProblem(prob.f, u₀, prob.tspan)
163+
sol = solve(_prob, Vern9(), save_everystep = false, save_start=false, save_end=false, callback=cb, abstol=1e-16, reltol=1e-16)
164+
scatter!(p, sol, vars=(3,4), markersize = 3, msw=0)
136165
end
137166

138167

139-
p = scatter(sol2, vars=(3,4), leg=false, markersize = 2, ylims=(-0.01,0.03))
140-
for i in -0.01:0.00125:0.01
141-
poincare_map(poincare, i, p)
168+
lβrange = -0.02:0.0025:0.02
169+
p = scatter(sol2, vars=(3,4), leg=false, markersize = 3, msw=0)
170+
forin lβrange
171+
poincare_map(poincare, [0.01, 0.01, 0.01, lβ], p)
142172
end
143-
plot(p,ylims=(-0.01,0.03))
173+
plot(p, xlabel="\\beta", ylabel="l_\\beta", ylims=(0, 0.03))
144174

145175

146176
using OrdinaryDiffEq, Plots
@@ -191,7 +221,7 @@ energy = map(x->E(x...), sol.u)
191221
@show ΔE = energy[1]-energy[end]
192222

193223
#Plot
194-
plot(sol.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
224+
plot(sol.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
195225

196226

197227
function HH_acceleration!(dv,v,u,p,t)
@@ -219,14 +249,14 @@ energy = map(x->E(x[3], x[4], x[1], x[2]), sol2.u)
219249
@show ΔE = energy[1]-energy[end]
220250

221251
#Plot
222-
plot(sol2.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
252+
plot(sol2.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
223253

224254

225255
sol3 = solve(prob, DPRKN6());
226256
energy = map(x->E(x[3], x[4], x[1], x[2]), sol3.u)
227257
@show ΔE = energy[1]-energy[end]
228258
gr()
229-
plot(sol3.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
259+
plot(sol3.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
230260

231261

232262
using DiffEqTutorials

tutorials/models/01-classical_physics.jmd

+112-43
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ author: Yingbo Ma, Chris Rackauckas
55

66
If you're getting some cold feet to jump in to DiffEq land, here are some handcrafted differential equations mini problems to hold your hand along the beginning of your journey.
77

8-
## Radioactive Decay of Carbon-14
8+
## First order linear ODE
99

10-
#### First order linear ODE
10+
#### Radioactive Decay of Carbon-14
1111

1212
$$f(t,u) = \frac{du}{dt}$$
1313

@@ -36,9 +36,67 @@ plot(sol,linewidth=2,title ="Carbon-14 half-life", xaxis = "Time in thousands of
3636
plot!(sol.t, t->exp(-C₁*t),lw=3,ls=:dash,label="Analytical Solution")
3737
```
3838

39-
## Simple Pendulum
39+
## Second Order Linear ODE
4040

41-
#### Second Order Linear ODE
41+
#### Simple Harmonic Oscillator
42+
43+
Another classical example is the harmonic oscillator, given by
44+
$$
45+
\ddot{x} + \omega^2 x = 0
46+
$$
47+
with the known analytical solution
48+
$$
49+
\begin{align*}
50+
x(t) &= A\cos(\omega t - \phi) \\
51+
v(t) &= -A\omega\sin(\omega t - \phi),
52+
\end{align*}
53+
$$
54+
where
55+
$$
56+
A = \sqrt{c_1 + c_2} \qquad\text{and}\qquad \tan \phi = \frac{c_2}{c_1}
57+
$$
58+
with $c_1, c_2$ constants determined by the initial conditions such that
59+
$c_1$ is the initial position and $\omega c_2$ is the initial velocity.
60+
61+
Instead of transforming this to a system of ODEs to solve with `ODEProblem`,
62+
we can use `SecondOrderODEProblem` as follows.
63+
64+
```julia
65+
# Simple Harmonic Oscillator Problem
66+
using OrdinaryDiffEq, Plots
67+
68+
#Parameters
69+
ω = 1
70+
71+
#Initial Conditions
72+
x₀ = [0.0]
73+
dx₀ = [π/2]
74+
tspan = (0.0, 2π)
75+
76+
ϕ = atan((dx₀[1]/ω)/x₀[1])
77+
A = √(x₀[1]^2 + dx₀[1]^2)
78+
79+
#Define the problem
80+
function harmonicoscillator(ddu,du,u,ω,t)
81+
ddu .= -ω^2 * u
82+
end
83+
84+
#Pass to solvers
85+
prob = SecondOrderODEProblem(harmonicoscillator, dx₀, x₀, tspan, ω)
86+
sol = solve(prob, DPRKN6())
87+
88+
#Plot
89+
plot(sol, vars=[2,1], linewidth=2, title ="Simple Harmonic Oscillator", xaxis = "Time", yaxis = "Elongation", label = ["x" "dx"])
90+
plot!(t->A*cos(ω*t-ϕ), lw=3, ls=:dash, label="Analytical Solution x")
91+
plot!(t->-A*ω*sin(ω*t-ϕ), lw=3, ls=:dash, label="Analytical Solution dx")
92+
```
93+
94+
Note that the order of the variables (and initial conditions) is `dx`, `x`.
95+
Thus, if we want the first series to be `x`, we have to flip the order with `vars=[2,1]`.
96+
97+
## Second Order Non-linear ODE
98+
99+
#### Simple Pendulum
42100

43101
We will start by solving the pendulum problem. In the physics class, we often solve this problem by small angle approximation, i.e. $ sin(\theta) \approx \theta$, because otherwise, we get an elliptic integral which doesn't have an analytic solution. The linearized form is
44102

@@ -48,6 +106,17 @@ But we have numerical ODE solvers! Why not solve the *real* pendulum?
48106

49107
$$\ddot{\theta} + \frac{g}{L}{\sin(\theta)} = 0$$
50108

109+
Notice that now we have a second order ODE.
110+
In order to use the same method as above, we nee to transform it into a system
111+
of first order ODEs by employing the notation $d\theta = \dot{\theta}$.
112+
113+
$$
114+
\begin{align*}
115+
&\dot{\theta} = d{\theta} \\
116+
&\dot{d\theta} = - \frac{g}{L}{\sin(\theta)}
117+
\end{align*}
118+
$$
119+
51120
```julia
52121
# Simple Pendulum Problem
53122
using OrdinaryDiffEq, Plots
@@ -62,18 +131,18 @@ tspan = (0.0,6.3)
62131

63132
#Define the problem
64133
function simplependulum(du,u,p,t)
65-
θ = u[1]
134+
θ = u[1]
66135
dθ = u[2]
67136
du[1] = dθ
68137
du[2] = -(g/L)*sin(θ)
69138
end
70139

71140
#Pass to solvers
72-
prob = ODEProblem(simplependulum,u₀, tspan)
141+
prob = ODEProblem(simplependulum, u₀, tspan)
73142
sol = solve(prob,Tsit5())
74143

75144
#Plot
76-
plot(sol,linewidth=2,title ="Simple Pendulum Problem", xaxis = "Time", yaxis = "Height", label = ["Theta","dTheta"])
145+
plot(sol,linewidth=2,title ="Simple Pendulum Problem", xaxis = "Time", yaxis = "Height", label = ["\\theta" "d\\theta"])
77146
```
78147

79148
So now we know that behaviour of the position versus time. However, it will be useful to us to look at the phase space of the pendulum, i.e., and representation of all possible states of the system in question (the pendulum) by looking at its velocity and position. Phase space analysis is ubiquitous in the analysis of dynamical systems, and thus we will provide a few facilities for it.
@@ -93,9 +162,21 @@ end
93162
plot(p,xlims = (-9,9))
94163
```
95164

96-
## Simple Harmonic Oscillator
165+
#### Double Pendulum
97166

98-
### Double Pendulum
167+
A more complicated example is given by the double pendulum. The equations governing
168+
its motion are given by the following (taken from this [StackOverflow question](https://mathematica.stackexchange.com/questions/40122/help-to-plot-poincar%C3%A9-section-for-double-pendulum))
169+
170+
$$\frac{d}{dt}
171+
\begin{pmatrix}
172+
\alpha \\ l_\alpha \\ \beta \\ l_\beta
173+
\end{pmatrix}=
174+
\begin{pmatrix}
175+
2\frac{l_\alpha - (1+\cos\beta)l_\beta}{3-\cos 2\beta} \\
176+
-2\sin\alpha - \sin(\alpha + \beta) \\
177+
2\frac{-(1+\cos\beta)l_\alpha + (3+2\cos\beta)l_\beta}{3-\cos2\beta}\\
178+
-\sin(\alpha+\beta) - 2\sin(\beta)\frac{(l_\alpha-l_\beta)l_\beta}{3-\cos2\beta} + 2\sin(2\beta)\frac{l_\alpha^2-2(1+\cos\beta)l_\alpha l_\beta + (3+2\cos\beta)l_\beta^2}{(3-\cos2\beta)^2}
179+
\end{pmatrix}$$
99180

100181
```julia
101182
#Double Pendulum Problem
@@ -138,33 +219,20 @@ ts, ps = polar2cart(sol, l1=L₁, l2=L₂, dt=0.01)
138219
plot(ps...)
139220
```
140221

141-
### Poincaré section
142-
143-
The Poincaré section is a contour plot of a higher-dimensional phase space diagram. It helps to understand the dynamic interactions and is wonderfully pretty.
144-
145-
The following equation came from [StackOverflow question](https://mathematica.stackexchange.com/questions/40122/help-to-plot-poincar%C3%A9-section-for-double-pendulum)
146-
147-
$$\frac{d}{dt}
148-
\begin{pmatrix}
149-
\alpha \\ l_\alpha \\ \beta \\ l_\beta
150-
\end{pmatrix}=
151-
\begin{pmatrix}
152-
2\frac{l_\alpha - (1+\cos\beta)l_\beta}{3-\cos 2\beta} \\
153-
-2\sin\alpha - \sin(\alpha + \beta) \\
154-
2\frac{-(1+\cos\beta)l_\alpha + (3+2\cos\beta)l_\beta}{3-\cos2\beta}\\
155-
-\sin(\alpha+\beta) - 2\sin(\beta)\frac{(l_\alpha-l_\beta)l_\beta}{3-\cos2\beta} + 2\sin(2\beta)\frac{l_\alpha^2-2(1+\cos\beta)l_\alpha l_\beta + (3+2\cos\beta)l_\beta^2}{(3-\cos2\beta)^2}
156-
\end{pmatrix}$$
222+
##### Poincaré section
157223

158-
The Poincaré section here is the collection of $(β,l_β)$ when $α=0$ and $\frac{dα}{dt}>0$.
224+
In this case the phase space is 4 dimensional and it cannot be easily visualized.
225+
Instead of looking at the full phase space, we can look at Poincaré sections,
226+
which are sections through a higher-dimensional phase space diagram.
227+
This helps to understand the dynamics of interactions and is wonderfully pretty.
159228

160-
#### Hamiltonian of a double pendulum
161-
Now we will plot the Hamiltonian of a double pendulum
229+
The Poincaré section in this is given by the collection of $(β,l_β)$ when $α=0$ and $\frac{dα}{dt}>0$.
162230

163231
```julia
164232
#Constants and setup
165233
using OrdinaryDiffEq
166234
initial2 = [0.01, 0.005, 0.01, 0.01]
167-
tspan2 = (0.,200.)
235+
tspan2 = (0.,500.)
168236

169237
#Define the problem
170238
function double_pendulum_hamiltonian(udot,u,p,t)
@@ -187,24 +255,25 @@ cb = ContinuousCallback(condition,affect!,nothing,
187255

188256
# Construct Problem
189257
poincare = ODEProblem(double_pendulum_hamiltonian, initial2, tspan2)
190-
sol2 = solve(poincare, Vern9(), save_everystep = false, callback=cb, abstol=1e-9)
258+
sol2 = solve(poincare, Vern9(), save_everystep = false, save_start=false, save_end=false, callback=cb, abstol=1e-16, reltol=1e-16,)
191259

192260
function poincare_map(prob, u₀, p; callback=cb)
193-
_prob = ODEProblem(prob.f,[0.01, 0.01, 0.01, u₀],prob.tspan)
194-
sol = solve(_prob, Vern9(), save_everystep = false, callback=cb, abstol=1e-9)
195-
scatter!(p, sol, vars=(3,4), markersize = 2)
261+
_prob = ODEProblem(prob.f, u₀, prob.tspan)
262+
sol = solve(_prob, Vern9(), save_everystep = false, save_start=false, save_end=false, callback=cb, abstol=1e-16, reltol=1e-16)
263+
scatter!(p, sol, vars=(3,4), markersize = 3, msw=0)
196264
end
197265
```
198266

199267
```julia
200-
p = scatter(sol2, vars=(3,4), leg=false, markersize = 2, ylims=(-0.01,0.03))
201-
for i in -0.01:0.00125:0.01
202-
poincare_map(poincare, i, p)
268+
lβrange = -0.02:0.0025:0.02
269+
p = scatter(sol2, vars=(3,4), leg=false, markersize = 3, msw=0)
270+
for lβ in lβrange
271+
poincare_map(poincare, [0.01, 0.01, 0.01, lβ], p)
203272
end
204-
plot(p,ylims=(-0.01,0.03))
273+
plot(p, xlabel="\\beta", ylabel="l_\\beta", ylims=(0, 0.03))
205274
```
206275

207-
## Hénon-Heiles System
276+
#### Hénon-Heiles System
208277

209278
The Hénon-Heiles potential occurs when non-linear motion of a star around a galactic center with the motion restricted to a plane.
210279

@@ -281,10 +350,10 @@ energy = map(x->E(x...), sol.u)
281350
@show ΔE = energy[1]-energy[end]
282351

283352
#Plot
284-
plot(sol.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
353+
plot(sol.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
285354
```
286355

287-
### Symplectic Integration
356+
##### Symplectic Integration
288357

289358
To prevent energy drift, we can instead use a symplectic integrator. We can directly define and solve the `SecondOrderODEProblem`:
290359

@@ -321,17 +390,17 @@ energy = map(x->E(x[3], x[4], x[1], x[2]), sol2.u)
321390
@show ΔE = energy[1]-energy[end]
322391

323392
#Plot
324-
plot(sol2.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
393+
plot(sol2.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
325394
```
326395

327-
It's so close to zero it breaks GR! And let's try to use a Runge-Kutta-Nyström solver to solve this. Note that Runge-Kutta-Nyström isn't symplectic.
396+
And let's try to use a Runge-Kutta-Nyström solver to solve this. Note that Runge-Kutta-Nyström isn't symplectic.
328397

329398
```julia
330399
sol3 = solve(prob, DPRKN6());
331400
energy = map(x->E(x[3], x[4], x[1], x[2]), sol3.u)
332401
@show ΔE = energy[1]-energy[end]
333402
gr()
334-
plot(sol3.t, energy, title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
403+
plot(sol3.t, energy .- energy[1], title = "Change in Energy over Time", xaxis = "Time in iterations", yaxis = "Change in Energy")
335404
```
336405

337406
Note that we are using the `DPRKN6` sovler at `reltol=1e-3` (the default), yet it has a smaller energy variation than `Vern9` at `abs_tol=1e-16, rel_tol=1e-16`. Therefore, using specialized solvers to solve its particular problem is very efficient.

0 commit comments

Comments
 (0)