codex/past-exam-of-the-medicine-course-of-the-university-of-oxford/1864/first-examination/physics-1864-clock-oscillators.py

past-exam-of-the-medicine-course-of-the-university-of-oxford/1864/first-examination/physics-1864-clock-oscillators.py
"""Ideal clock restoring mechanisms; write an opaque PNG to the current directory."""
from pathlib import Path
import os

ROOT = next(p for p in Path(__file__).resolve().parents if (p / "ourbigbook.json").exists())
os.environ.setdefault("MPLCONFIGDIR", str(ROOT / "_out/matplotlib"))

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Circle, Arc
import numpy as np


def draw():
    plt.rcParams.update({"font.size": 12, "axes.titlesize": 14})
    fig, (pendulum, balance) = plt.subplots(1, 2, figsize=(12, 5), dpi=120, facecolor="white")
    blue, orange = "#0072B2", "#D55E00"
    length, theta = 2.05, .48
    bob = np.array([length * np.sin(theta), -length * np.cos(theta)])
    pendulum.plot([-.4, .4], [.06, .06], color="#555555", lw=4)
    pendulum.plot([0, 0], [0, -2.35], "--", color="#888888", lw=1)
    pendulum.plot([0, bob[0]], [0, bob[1]], color=blue, lw=3)
    pendulum.add_patch(Circle(bob, .16, facecolor=blue, zorder=4))
    pendulum.add_patch(Circle((0, 0), .045, facecolor="#222222", zorder=5))
    pendulum.add_patch(Arc((0, 0), 1.02, 1.02, theta1=270, theta2=270+np.degrees(theta),
                           color="#555555", lw=1.5))
    pendulum.text(.18, -.7, r"$\theta$", fontsize=16)
    pendulum.text(.65, -.8, r"$L$", fontsize=16, color=blue)
    pendulum.annotate("", xy=bob+[0, -.65], xytext=bob,
                      arrowprops={"arrowstyle": "->", "lw": 2.4, "color": orange})
    pendulum.text(bob[0]+.1, bob[1]-.49, r"$mg$", color=orange, fontsize=15)
    pendulum.text(-1.05, -.85, "Gravity supplies\nthe restoring torque", ha="center", fontsize=12)
    pendulum.text(0, -2.8, r"$\tau=-mgL\sin\theta$", ha="center", fontsize=16)
    pendulum.text(0, -3.25, r"$T\simeq2\pi\sqrt{L/g}$", ha="center", fontsize=16)
    pendulum.set_title("Pendulum: small-angle gravitational oscillator")
    pendulum.set_xlim(-1.75, 1.75)
    pendulum.set_ylim(-3.55, .35)

    radius, angle = 1.05, .35
    balance.add_patch(Circle((0, -.9), radius, fill=False, edgecolor=blue, lw=4))
    for offset in (0, np.pi/2):
        v = radius*np.array([np.cos(angle+offset), np.sin(angle+offset)])
        balance.plot([-v[0], v[0]], [-.9-v[1], -.9+v[1]], color=blue, lw=2)
    t = np.linspace(0, 6*np.pi, 600)
    r = .08+.68*t/t[-1]
    balance.plot(r*np.cos(t), -.9+r*np.sin(t), color=orange, lw=1.7)
    balance.plot([.76, 1.43], [-.9, -.9], color=orange, lw=1.8)
    balance.plot([1.43, 1.43], [-1.1, -.7], color="#555555", lw=4)
    balance.add_patch(Circle((0, -.9), .045, color="#222222", zorder=5))
    balance.annotate("Fixed outer end", xy=(1.43, -.9), xytext=(.7, .4),
                     arrowprops={"arrowstyle": "->", "color": "#555555"}, ha="center", fontsize=11)
    balance.annotate("Spiral spring", xy=(.33, -.6), xytext=(-1.03, .35),
                     arrowprops={"arrowstyle": "->", "color": orange}, ha="center", fontsize=11)
    balance.text(0, -2.25, "Elasticity supplies the restoring torque", ha="center", fontsize=12)
    balance.text(0, -2.8, r"$\tau\simeq-\kappa\phi$", ha="center", fontsize=16)
    balance.text(0, -3.25, r"$T\simeq2\pi\sqrt{I/\kappa}$", ha="center", fontsize=16)
    balance.set_title("Balance wheel: elastic angular oscillator")
    balance.set_xlim(-1.75, 1.75)
    balance.set_ylim(-3.55, .65)
    for ax in (pendulum, balance):
        ax.set_aspect("equal")
        ax.axis("off")
    fig.suptitle("Two clock regulators: restoring action plus inertia", fontsize=17)
    fig.tight_layout(rect=(0, 0, 1, .93))
    fig.savefig(Path.cwd() / "physics-1864-clock-oscillators.png", facecolor="white",
                transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    draw()