# Three bars meeting at a free node; all other nodes pinned.
# Bar 1: horizontal (angle 0°), AE=1, L=1
# Bar 2: vertical (angle 90°), AE=1, L=1
# Bar 3: diagonal (angle 45°), AE=1, L=sqrt(2)
AE_val = 100e3 # N (typical for thin steel bar)
def bar_stiffness(AE, L, angle_deg):
"""Local stiffness contribution to 2-DOF free node"""
th = np.radians(angle_deg)
cx, cy = np.cos(th), np.sin(th)
return (AE/L)*np.array([[cx**2, cx*cy],[cx*cy, cy**2]])
K_global = np.zeros((2,2))
bars_info = [(AE_val, 1.0, 0), # horizontal
(AE_val, 1.0, 90), # vertical
(AE_val, np.sqrt(2), 45)] # diagonal
for AE_b, L_b, ang in bars_info:
K_global += bar_stiffness(AE_b, L_b, ang)
F_applied = np.array([10e3, -20e3]) # 10 kN right, 20 kN down
u_disp = solve(K_global, F_applied)
print(f"Global stiffness matrix K [N/m]:\n{np.round(K_global,1)}\n")
print(f"Applied force F = {F_applied/1e3} kN")
print(f"Displacements u = [{u_disp[0]*1e6:.2f}, {u_disp[1]*1e6:.2f}] µm")
print(f"Residual ||Ku-F|| = {norm(K_global@u_disp - F_applied):.2e}")
# Plot truss
fig, ax = plt.subplots(figsize=(6,5))
node_free = np.array([1.0, 1.0]) # free node at center
nodes = {'A':[0,1], 'B':[1,0], 'C':[2,1], 'Free':[1,1]}
bar_conns = [('A','Free'), ('B','Free'), ('C','Free')]
colors_b = ['steelblue','crimson','seagreen']
for (n1,n2), col in zip(bar_conns, colors_b):
p1, p2 = np.array(nodes[n1]), np.array(nodes[n2])
ax.plot([p1[0],p2[0]], [p1[1],p2[1]], '-', color=col, lw=3)
for name, pos in nodes.items():
ax.plot(*pos, 'ko', markersize=10, zorder=5)
ax.text(pos[0]+0.05, pos[1]+0.08, name, fontsize=10)
ax.annotate('', xy=node_free+np.array([0.3,0]), xytext=node_free,
arrowprops=dict(arrowstyle='->', color='darkorange', lw=2.5))
ax.annotate('', xy=node_free+np.array([0,-0.3]), xytext=node_free,
arrowprops=dict(arrowstyle='->', color='darkorange', lw=2.5))
ax.text(node_free[0]+0.32, node_free[1]+0.02, '$F_x$', color='darkorange')
ax.text(node_free[0]+0.05, node_free[1]-0.35, '$F_y$', color='darkorange')
ax.set_aspect('equal'); ax.set_xlim(-0.3, 2.5); ax.set_ylim(0.3, 1.6)
ax.set_title('3-bar pin-jointed truss: $K\\mathbf{u}=\\mathbf{f}$')
ax.axis('off')
plt.tight_layout(); plt.show()