codexsphere-drag-coefficient-stokes-limit.py
sphere-drag-coefficient-stokes-limit.py
"""Plot the creeping-limit approximation; write an opaque PNG to CWD.
Tested with Python 3.14.4, NumPy 2.3.5 and Matplotlib 3.10.7.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
def main():
reynolds = np.logspace(-4, -1, 401)
toy_re = np.array([0.002, 0.004])
fig, ax = plt.subplots(figsize=(7.4, 4.7), dpi=120)
fig.patch.set_facecolor("white")
ax.set_facecolor("white")
ax.loglog(reynolds, 24 / reynolds, color="#246a9b", lw=2.5,
label=r"Creeping-limit approximation: $C_D=24/\mathrm{Re}_d$")
ax.scatter(toy_re, 24 / toy_re, color=["#ba5739", "#754c9b"], s=55, zorder=4)
for re, cd, label, offset in [(0.002, 12000, r"$U_0$: (0.002, 12000)", (-90, 28)),
(0.004, 6000, r"$2U_0$: (0.004, 6000)", (18, -5))]:
ax.annotate(label, (re, cd), xytext=offset, textcoords="offset points",
fontsize=10, arrowprops={"arrowstyle": "-", "color": "#555555"})
ax.set(xlim=(1e-4, 1e-1), ylim=(180, 3e5),
xlabel=r"Diameter-based Reynolds number $\mathrm{Re}_d=2a\rho U/\mu$",
ylabel=r"Drag coefficient $C_D$ (frontal area $A=\pi a^2$)",
title="Sphere drag coefficient in the creeping-flow approximation")
ax.grid(True, which="both", alpha=0.18)
ax.legend(loc="upper right", fontsize=9)
fig.text(0.5, 0.035, "Mathematical small-Re approximation; not empirical data or an all-Re law.",
ha="center", fontsize=10)
fig.tight_layout(rect=(0, 0.075, 1, 1))
fig.savefig(Path.cwd() / "sphere-drag-coefficient-stokes-limit.png",
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()