codexrotational-diffusion-sphere-size-scaling.py
rotational-diffusion-sphere-size-scaling.py
"""Original bulk-sphere size scaling and 3D vector memory; Python 3.14.
Run from the output directory. Requires numpy 2.3.5 and matplotlib 3.10.7.
These are chosen model predictions, not a fit to confined ellipsoid data.
"""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def main():
plt.rcParams.update({"font.size": 11, "axes.spines.top": False,
"axes.spines.right": False, "figure.facecolor": "white"})
blue, orange = "#176b9b", "#c65b17"
kb, temperature, eta = 1.380649e-23, 298.0, 0.001
radius_um = np.geomspace(0.1, 1, 400)
radius = radius_um * 1e-6
dr = kb*temperature / (8*np.pi*eta*radius**3)
dt = kb*temperature / (6*np.pi*eta*radius)
fig, axes = plt.subplots(1, 2, figsize=(11.2, 5.0), dpi=100, layout="constrained")
ax = axes[0]
ax.loglog(radius_um, dr/dr[-1], color=blue, lw=2.5,
label=r"Rotation: $D_r/D_r(1\,\mu\mathrm{m})\propto a^{-3}$")
ax.loglog(radius_um, dt/dt[-1], color=orange, lw=2.5, ls="--",
label=r"Translation: $D_t/D_t(1\,\mu\mathrm{m})\propto a^{-1}$")
ax.plot([0.1, 1], [1000, 1], "o", color=blue)
ax.plot([0.1, 1], [10, 1], "s", color=orange)
ax.set(xlim=(0.085, 1.18), ylim=(0.7, 1800), xlabel=r"Sphere radius $a$ ($\mu$m)",
ylabel="Coefficient / its value at radius 1 µm",
title="Ten times smaller: 1000× faster rotation")
ax.set_xticks([0.1, 0.2, 0.5, 1], ["0.1", "0.2", "0.5", "1"])
ax.set_yticks([1, 10, 100, 1000], ["1", "10", "100", "1000"])
ax.grid(which="major", alpha=0.18)
ax.legend(loc="upper right", frameon=False, fontsize=10)
ax = axes[1]
t = np.geomspace(1e-4, 20, 700)
for radius_m, color, label, ypos in [(1e-7, blue, "0.1 µm", 0.57),
(1e-6, orange, "1 µm", 0.15)]:
rate = kb*temperature/(8*np.pi*eta*radius_m**3)
tau = 1/(2*rate)
ax.semilogx(t, np.exp(-2*rate*t), color=color, lw=2.5, label=label)
ax.plot(tau, np.exp(-1), "o", color=color)
ax.axvline(tau, color=color, ls=":", lw=1)
ax.text(0.04, ypos, f"a = {label}: Dᵣ = {rate:.3g} s⁻¹\n"
+ (f"τ = {tau*1000:.3g} ms" if tau < 0.1 else f"τ = {tau:.3g} s"),
transform=ax.transAxes, color=color, fontsize=10,
bbox={"facecolor": "white", "edgecolor": "none", "alpha": 0.88})
ax.axhline(np.exp(-1), color="#888888", ls="--", lw=0.8)
ax.text(11, np.exp(-1)+0.035, r"$1/e$", ha="right", color="#666666")
ax.set(xlim=(1e-4, 20), ylim=(0, 1.05), xlabel="Lag time (s; logarithmic scale)",
ylabel=r"$C_1(t)=\langle\mathbf{u}(t)\cdot\mathbf{u}(0)\rangle$",
title=r"3D vector memory: $C_1=e^{-2D_rt}$")
ax.legend(title="Radius", loc="upper right", frameon=False, fontsize=10)
fig.suptitle("Bulk no-slip spheres: size sets the rotational memory time", fontsize=15, weight="bold")
fig.supxlabel("Chosen model: T = 298 K, η = 0.001 Pa s; a visible marker defines the vector.\n"
"Predictions for unbounded fluid, not an ellipsoid fit or experimental data.", fontsize=10)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()