fork download
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from matplotlib.animation import FuncAnimation
  4. from matplotlib.patches import Circle, Polygon
  5.  
  6. # Parameters
  7. U_INF = 1.0
  8. R = 0.8
  9. LAMBDA = 0.15
  10. CIRCLE_CENTER = -0.1 + 0.1j
  11. GRID_RESOLUTION = 500
  12. N_STREAMLINES = 12
  13.  
  14. # Grid setup
  15. x = np.linspace(-2, 2, GRID_RESOLUTION)
  16. y = np.linspace(-2, 2, GRID_RESOLUTION)
  17. X, Y = np.meshgrid(x, y)
  18. Z = X + 1j*Y
  19.  
  20. # Velocity field (circle)
  21. radius = np.sqrt((X - np.real(CIRCLE_CENTER))**2 + (Y - np.imag(CIRCLE_CENTER))**2)
  22. theta = np.arctan2(Y - np.imag(CIRCLE_CENTER), X - np.real(CIRCLE_CENTER))
  23. U_r = U_INF * (1 - (R**2) / (radius**2)) * np.cos(theta)
  24. U_theta = -U_INF * (1 + (R**2) / (radius**2)) * np.sin(theta)
  25. U = U_r * np.cos(theta) - U_theta * np.sin(theta)
  26. V = U_r * np.sin(theta) + U_theta * np.cos(theta)
  27.  
  28. # Joukowsky transform
  29. def joukowsky(z, lambda_=LAMBDA):
  30. return z + lambda_**2 / z
  31.  
  32. theta_circle = np.linspace(0, 2*np.pi, 200)
  33. circle_points = R * np.exp(1j * theta_circle) + CIRCLE_CENTER
  34. airfoil_points = joukowsky(circle_points)
  35.  
  36. # Streamlines
  37. start_points = np.column_stack([
  38. -2 * np.ones(N_STREAMLINES),
  39. np.linspace(-1.5, 1.5, N_STREAMLINES)
  40. ])
  41.  
  42. # Animation
  43. fig, ax = plt.subplots(figsize=(10, 6))
  44. ax.set_xlim(-2, 2)
  45. ax.set_ylim(-2, 2)
  46. ax.set_facecolor('black')
  47. ax.set_xticks([])
  48. ax.set_yticks([])
  49.  
  50. STREAMLINE_COLOR = '#E63946'
  51.  
  52. def update(frame):
  53. ax.clear()
  54. ax.set_xlim(-2, 2)
  55. ax.set_ylim(-2, 2)
  56.  
  57. lambda_ = LAMBDA * (frame / 30)
  58. transformed_points = joukowsky(circle_points, lambda_)
  59.  
  60. # Fixed Circle constructor
  61. if lambda_ == 0:
  62. shape = Circle((np.real(CIRCLE_CENTER), np.imag(CIRCLE_CENTER)), R,
  63. fc='#FAF9F6', ec='none', zorder=3)
  64. else:
  65. shape = Polygon(np.column_stack([np.real(transformed_points), np.imag(transformed_points)]),
  66. fc='#FAF9F6', ec='none', zorder=3)
  67. ax.add_patch(shape)
  68.  
  69. strm = ax.streamplot(X, Y, U, V, color=STREAMLINE_COLOR, linewidth=1.5,
  70. start_points=start_points, arrowsize=0, zorder=2)
  71.  
  72. for path in strm.lines.get_segments():
  73. for i in range(0, len(path) - 8, 8):
  74. p_start, p_end = path[i], path[i+1]
  75. ax.arrow(p_start[0], p_start[1], p_end[0]-p_start[0], p_end[1]-p_start[1],
  76. shape='full', lw=1, head_width=0.05, head_length=0.1,
  77. color=STREAMLINE_COLOR, zorder=2)
  78.  
  79. ax.set_title(f"Joukowsky Transformation (λ={lambda_:.2f})", color='white')
  80.  
  81. ani = FuncAnimation(fig, update, frames=30, interval=100, blit=False)
  82. plt.tight_layout()
  83. plt.show()
Success #stdin #stdout #stderr 3.52s 94392KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
Fontconfig error: No writable cache directories
/usr/local/lib/python3.12/dist-packages/matplotlib/animation.py:892: UserWarning: Animation was deleted without rendering anything. This is most likely not intended. To prevent deletion, assign the Animation to a variable, e.g. `anim`, that exists until you output the Animation using `plt.show()` or `anim.save()`.