UnbreakableMass, CC BY-SA 3.0 <https://creativecommons.org/licenses/by-sa/3.0>, via Wikimedia Commons
In today's article, we'll cover a counterintuitive, seemingly paraxodical physical effect, how to use event-triggered termination of ordinary differential equation solving on Python, and all along some practice in Lagrangian mechanics.
The effect is this: Consider an object falling freely from height \(L\). When it hits the ground, it has some velocity. So far, nothing special. Now consider a tower of height \(L\), falling freely to the side. Does the tower have the same velocity when it hits the ground? Spontaneously, out of reflex (thinking of Galileo), I would have said: yes. But closer examination shows that this is not at all the case. And what's even more intruiguing: The tower is faster! Let's see why.
Free Fall
First of all, let's treat the object falling freely from height \(y = L\). To calculate its velocity when it hits the ground, we simply invoke energy conservation.
Initially, when at height \(L\), the object has zero velocity, so its kinetic
energy is zero and the potential energy is simply \(m g L\). So we have
$$
E = m g L
$$
When it hits the ground, it has zero potential energy (because the height \(y\) is now
0) and the total energy is just from kinetic energy. So we have
$$
E = \frac{m}{2}v^2.
$$
Solving for \(v\), we get
$$
v = \sqrt{2 g L}
$$
That was all too easy. So now let's consider this other, curious example.
Falling Tower
Consider a "tower", and suppose it is falling to the side. What we
want to calculate is this: When the tower hits the ground, what is the speed of the top
of the tower?
The problem can be easily solved using Lagrangian mechanics. If you want to brush up on this
topic, have a look at this article .
In Lagrangian mechanics, we basically just have to choose the most convenient
coordinates and then formulate the Lagrangian, which is simply the difference of
kinetic and potential energy, expressed in our coordinates of choice. Then we solve
the corresponding socalled Euler-Lagrange equations. So, here it goes.
The most convenient coordinate is the angle between the ground and the tip of the tower.
When it is \(\varphi=\pi/2\), the tower is still standing, when it is \(\varphi = 0\), the tower is
on the ground.
We will consider the tower as one-dimensional with constant linear mass density \(\mu\). So,
a line element \(dl\) along the tower has the mass \(dm=\mu dl\). The line element is at height
\(y = l \).
Line element \(dl\) at length \(l\) away from origin is at height \(l \sin \varphi\), so it has potential energy
$$
dV = \mu l \sin \varphi dl
$$
The total potential energy of the tower is then just then integral
$$
V = \mu g \sin\varphi \int_0^L l dl = \frac{1}{2} g \mu L^2\sin\varphi
$$
The velocity of each line element can only have a component perpendicular to the
tower. So the kinetic energy is
This is what we need to solve. It can't be done analytically, so we solve it numerically using Python. To do this, we have to bring our equation into standard form
We want to solve that with scipy's ODE solver. But there's a catch. Normally,
when we are solving an initial value problem like this, we ask the solver to
give us the solution from time t=0 to some fixed time t_end. But what is t_end?
Well, it's the time when the tower hits the ground, but we don't know what its numeric
value is, yet! How can we tell the solver what we want it to do? Look at the signature
of the solve_ivp function from scipy:
What we need is the events keyword. We can tell the solver that it look for certain events while solving the problem. And if we do so, we solver will remember when and under what conditions these events occur. In our case, the event we are interested in is when the tower hits the ground, so when \(\varphi = 0\). The events keyword wants a callable (or a list of callables, if we want to watch more than just one event). Each callable must be of the form event(t, y) and must return a float value. The solver will insert the current time and current value at each step and evaluate that function. If it returns 0, the event triggers, if it is not equal to zero, it does not trigger. In our case, we want it to trigger, when \(\varphi=0\), and \(\varphi\) corresponds to y[0]. So we write
def termination_event(t, y):
return y[0]
We could pass that to the solver, but then it would just record when this event fires. It would not terminate integration. However, we can tell it to do so. We just have to attach a property called terminal to the callable:
from scipy.integrate import solve_ivp
L = 30 # meters
g = 9.81 # Earth gravitational constant in m / s**2
def f(t, y):
phi = y[0]
return [y[1], -1.5 * g/ L * np.cos(y[0])]
# we have to give it a little "push", otherwise it will stand still
eps = 1.E-3
y_init = [np.pi / 2-eps, 0]
sol = solve_ivp(f, (0, 100), y_init, events=termination_event)
Let's have a look at what this output means. The message indicates that the solver
has found our termination condition. That's good. This termination condition occurred
at time \(t=11.5737s\) (t_events). At this time, the solution was
The first argument is \(\varphi\), the second is the angular velocity at that time.
Our terminal speed is then
$$
v = L \dot \varphi
$$
Let's compare this with the terminal velocity for free fall, and let's look at
the dependency on \(L\).
import numpy as np
import matplotlib.pyplot as plt
Ls = np.linspace(10, 100, 100)
vs = []
for L in Ls:
def f(t, y):
phi = y[0]
return [y[1], -1.5 * g / L * np.cos(y[0])]
sol = solve_ivp(f, (0, 100), y_init, events=termination_event)
if sol.y_events:
v = abs(L * sol.y_events[0][0, 1])
vs.append(v)
else:
print(L, "did not succeed")
vs = np.array(vs)
vs_free = np.sqrt(2*g*Ls)
plt.plot(Ls, vs_free, lw=4, label="free")
plt.plot(Ls, vs, lw=4, label="tower")
plt.plot(Ls, vs_free * np.sqrt(3/2), "-.", lw=2, label=r"free $\cdot \sqrt{3/2}$")
plt.xlabel("height L (m)")
plt.ylabel("terminal velocity (m/s)")
plt.legend()
plt.grid()
As you can see, the tip of the tower always has a higher speed than an object
falling freely from the same height. By how much? That's why I also plotted the
curve for free fall, scaled by a factor of \(\sqrt{3/2}\), and it's right on top
of the curve for the tower. So, as a result, we now know the analytic expression
for the terminal speed of the tip of the tower. It's