"""Original contact-complementarity set and initial block lift-off response.""" from pathlib import Path import matplotlib.pyplot as plt import numpy as np def main(): mass, gravity = 2.0, 9.81 pull = np.linspace(0, 30, 1501) reaction = np.maximum(mass * gravity - pull, 0) acceleration = np.maximum((pull - mass * gravity) / mass, 0) assert np.allclose(reaction + pull - mass * gravity, mass * acceleration) assert np.allclose(reaction * acceleration, 0) assert np.isclose(mass * gravity - 5, 14.62) assert np.isclose((25 - mass * gravity) / mass, 2.69) fig, (allowed, release) = plt.subplots(1, 2, figsize=(10, 4.3), dpi=100, layout="constrained") fig.set_facecolor("white") allowed.axvspan(0, 2.2, color="#eeeeee", zorder=0) allowed.plot([0, 0], [0, 25], color="#286f99", linewidth=3) allowed.plot([0, 2.2], [0, 0], color="#286f99", linewidth=3) allowed.scatter([0, 0, 1.6], [0, 15, 0], color="#286f99", s=38, zorder=4) allowed.scatter([1.0], [10], color="#9f4b27", marker="x", s=65, linewidth=2, zorder=5) allowed.annotate("Loaded contact", (0, 15), xytext=(0.32, 18), fontsize=9, arrowprops={"arrowstyle": "->", "color": "#286f99"}) allowed.annotate("Unloaded touch", (0, 0), xytext=(0.25, 4), fontsize=9, arrowprops={"arrowstyle": "->", "color": "#286f99"}) allowed.annotate("Open contact", (1.6, 0), xytext=(1.27, 3), fontsize=9, arrowprops={"arrowstyle": "->", "color": "#286f99"}) allowed.text(0.75, 12, "Positive gap and force:\nexcluded", fontsize=9, color="#9f4b27") allowed.set(xlim=(-0.08, 2.2), ylim=(-1, 25), xticks=[0, 1, 2], xlabel="Normal gap (mm)", ylabel="Normal force (N)", title="Complementarity allows only the blue axes") force_line, = release.plot(pull, reaction, color="#286f99", linewidth=2, label="Initial normal reaction") release.set(xlim=(0, 30), ylim=(-1, 21), xlabel="Upward applied force (N)", ylabel="Initial normal reaction (N)", title="Lift-off when the upward pull exceeds mg") release.tick_params(axis="y", labelcolor="#286f99") accel_axes = release.twinx() accel_line, = accel_axes.plot(pull, acceleration, "--", color="#9f4b27", linewidth=2, label="Initial upward acceleration") accel_axes.set(ylim=(-0.28, 5.88), ylabel="Initial upward acceleration (m/s²)") accel_axes.tick_params(axis="y", labelcolor="#9f4b27") release.axvline(mass * gravity, color="#777777", linestyle=":", linewidth=1) release.scatter([5], [14.62], color="#286f99", zorder=5) accel_axes.scatter([25], [2.69], color="#9f4b27", zorder=5) release.annotate("5 N pull: 14.62 N reaction", (5, 14.62), xytext=(2, 10.5), fontsize=8.5, arrowprops={"arrowstyle": "->", "color": "#286f99"}) release.legend(handles=[force_line, accel_line], loc="upper right", fontsize=8) for ax in (allowed, release): ax.grid(alpha=0.12) fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white") plt.close(fig) if __name__ == "__main__": main()