wave_equation1d.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. """Simulate a discrete collection of oscillators
  2. We will use this as a model of a vibrating string and
  3. compare two methods of integration: Euler (red) and Runge-Kutta4 (green).
  4. For too large values of dt the simple Euler will diverge."""
  5. # To model 'N' oscillators, we will use N+2 Points, numbered
  6. # 0, 1, 2, 3, ... N+1. Points 0 and N+1 are actually the boundaries.
  7. # We will keep them fixed, but adding them in as if they were
  8. # masses makes the programming easier.
  9. # Adapted from B.Martin (2009) http://www.kcvs.ca/martin by M.Musy
  10. from vedo import *
  11. ####################################################
  12. N = 400 # Number of coupled oscillators
  13. dt = 0.5 # Time step
  14. nsteps = 2000 # Number of steps in the simulation
  15. ####################################################
  16. # Initial positions
  17. ####################################################
  18. x = np.array(list(range(N + 2)))
  19. z = np.zeros(N + 2, float)
  20. y = np.zeros(N + 2, float) # y[p] is the position of particle p
  21. for p in x: # p is particle number along x axis
  22. y[p] = 100 * np.sin(p/15) * np.exp(-p/50)
  23. ####################################################
  24. # Initial velocities
  25. ####################################################
  26. v = np.zeros(N + 2, float)
  27. # or you can give one specific particle a kick:
  28. # v[40] = 50
  29. ####################################################
  30. # Integrate forward
  31. ####################################################
  32. # Acceleration function for the simple harmonic oscillator
  33. def accel(y, v, t):
  34. a = np.zeros(N + 2, float) # acceleration of particles
  35. a[1 : N+1] = -(y[1 : N+1] - y[0:N]) - (y[1 : N+1] - y[2 : N+2])
  36. return a
  37. def runge_kutta4(y, v, t, dt): # 4th Order Runge-Kutta
  38. yk1 = dt * v
  39. vk1 = dt * accel(y, v, t)
  40. yk2 = dt * (v + vk1 / 2)
  41. vk2 = dt * accel(y + yk1 / 2, v + vk1 / 2, t + dt / 2)
  42. yk3 = dt * (v + vk2 / 2)
  43. vk3 = dt * accel(y + yk2 / 2, v + vk2 / 2, t + dt / 2)
  44. yk4 = dt * (v + vk3)
  45. vk4 = dt * accel(y + yk3, v + vk3, t + dt)
  46. ynew = y + (yk1 + 2 * yk2 + 2 * yk3 + yk4) / 6
  47. vnew = v + (vk1 + 2 * vk2 + 2 * vk3 + vk4) / 6
  48. return ynew, vnew
  49. def euler(y, v, t, dt): # simple euler integrator
  50. vnew = v + accel(y, v, t) * dt
  51. ynew = y + vnew * dt + 1 / 2 * accel(y, vnew, t) * dt ** 2
  52. return ynew, vnew
  53. positions_eu, positions_rk = [], []
  54. y_eu, y_rk = np.array(y), np.array(y)
  55. v_eu, v_rk = np.array(v), np.array(v)
  56. t = 0
  57. for i in progressbar(nsteps, c="b", title="integrating RK4 and Euler"):
  58. y_eu, v_eu = euler(y_eu, v_eu, t, dt)
  59. y_rk, v_rk = runge_kutta4(y_rk, v_rk, t, dt)
  60. t += dt
  61. positions_eu.append(y_eu) # store result of integration
  62. positions_rk.append(y_rk)
  63. ####################################################
  64. # Visualize the result
  65. ####################################################
  66. plt = Plotter(interactive=False, axes=2, size=(1400,1000))
  67. line_eu = Line([0,0,0], [len(x)-1,0,0], res=len(x)).c("red5").lw(5)
  68. plt += line_eu
  69. line_rk = Line([0,0,0], [len(x)-1,0,0], res=len(x)).c("green5").lw(5)
  70. plt += line_rk
  71. # let's also add a fancy background image from wikipedia
  72. img = dataurl + "images/wave_wiki.png"
  73. plt += Image(img).alpha(0.8).scale(0.4).pos(0,-100,-1)
  74. plt += __doc__
  75. plt.show(zoom=1.5)
  76. for i in progressbar(nsteps, title="visualize the result", c='y'):
  77. if i%10 != 0:
  78. continue
  79. y_eu = positions_eu[i] # retrieve the list of y positions at step i
  80. y_rk = positions_rk[i]
  81. pts = line_eu.points
  82. pts[:,1] = y_eu
  83. line_eu.points = pts
  84. pts = line_rk.points
  85. pts[:,1] = y_rk
  86. line_rk.points = pts
  87. plt.render()
  88. plt.interactive().close()