codexcircular-hole-stress-concentration.py
circular-hole-stress-concentration.py
"""Kirsch boundary stress for a circular hole under remote horizontal tension."""
from pathlib import Path
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import Normalize
import numpy as np
def main():
theta = np.linspace(0, 2*np.pi, 721)
tangential = 1 - 2*np.cos(2*theta)
assert np.isclose(tangential.min(), -1)
assert np.isclose(tangential.max(), 3)
assert np.allclose(1 - 2*np.cos(2*np.array([0, np.pi/2, np.pi, 3*np.pi/2])),
[-1, 3, -1, 3])
fig, (hole, curve) = plt.subplots(1, 2, figsize=(9, 4.1), dpi=100,
layout="constrained", width_ratios=[1, 1.15])
fig.set_facecolor("white")
points = np.column_stack([np.cos(theta), np.sin(theta)])
lines = LineCollection(np.stack([points[:-1], points[1:]], axis=1),
cmap="coolwarm", norm=Normalize(-1, 3), linewidth=6)
lines.set_array((tangential[:-1]+tangential[1:])/2)
hole.add_collection(lines)
for y in [-.7, 0, .7]:
for start, end in [(1.7, 2.5), (-1.7, -2.5)]:
hole.annotate("", (end, y), (start, y),
arrowprops=dict(arrowstyle="->", color="#555555", lw=1.5))
hole.text(0, 1.33, "3σ∞", ha="center", color="#aa2222", fontsize=12)
hole.text(0, -1.55, "3σ∞", ha="center", color="#aa2222", fontsize=12)
hole.text(0, 0, "Hole\n(radial traction = 0)", ha="center", va="center", fontsize=10)
hole.text(0, 1.9, "Remote tension along x", ha="center")
hole.set(xlim=(-2.8, 2.8), ylim=(-2, 2.3), aspect="equal",
title="Tangential stress at the boundary")
hole.axis("off")
curve.plot(np.degrees(theta), tangential, color="#1565c0", lw=2)
curve.axhline(0, color="#aaaaaa", lw=.8)
curve.scatter([0, 90, 180, 270, 360], [-1, 3, -1, 3, -1],
color=["#1565c0", "#aa2222", "#1565c0", "#aa2222", "#1565c0"])
curve.set(xlim=(0, 360), ylim=(-1.5, 3.5), xticks=[0, 90, 180, 270, 360],
yticks=[-1, 0, 1, 2, 3], xlabel="Angle θ from loading direction (degrees)",
ylabel="Tangential stress / remote tensile stress",
title="σθθ(a, θ) / σ∞ = 1 − 2 cos(2θ)")
curve.grid(alpha=.2)
fig.savefig(Path(__file__).with_suffix(".png").name, facecolor="white")
plt.close(fig)
if __name__ == "__main__":
main()