Advertisement
Guest User

Untitled

a guest
Oct 23rd, 2019
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.54 KB | None | 0 0
  1. # coding=utf-8
  2.  
  3. from __future__ import unicode_literals, print_function, division
  4. from visual import window, cylinder, ring, random, sphere, mag, sleep, rate, mag2, dot, norm, cross, exit
  5. from visual.graph import display, vector, color, gdisplay, gcurve, ghistogram, arange
  6. from math import sqrt, pi, cos, sin, exp, asin
  7. import wx
  8.  
  9. still_working = 0
  10. win_height = 570
  11. win_width = 1100
  12. # здесь появляется нечто новое :)
  13. ampl = 0 # амплитуда движения
  14. period = 5
  15. Natoms = 30 # change this to have more or fewer atoms
  16. Natoms1 = 10
  17. mass = 4E-3 / 6E23 # helium mass
  18. mass1 = mass / 2
  19. Ratom = 0.06 # wildly exaggerated size of helium atom
  20. k = 1.4E-23 # Boltzmann constant
  21. R = 8.3
  22. T = 300 # around room temperature
  23. dt = 1E-5
  24. w = window(width=win_width + 2 * window.dwidth,
  25. height=win_height + window.dheight,
  26. title='Модель динамики газа в поршне',
  27. style=wx.CAPTION | wx.CLOSE_BOX)
  28. p = w.panel
  29.  
  30. t1 = wx.RadioBox(p, pos=(win_width - 270, 12), size=(270, 120),
  31. choices=['Вариант движения 1', 'Вариант движения 2'], style=wx.RA_SPECIFY_ROWS)
  32.  
  33. def setampl(evt): # установление амплитуды
  34. ampl = amplslider.GetValue()
  35.  
  36. amplslider = wx.Slider(p, pos=(win_width - 270, 170), size=(270, 20), minValue=0, maxValue=500)
  37. amplslider.Bind(wx.EVT_SCROLL, setampl)
  38. wx.StaticText(p, pos=(win_width - 270, 140), label='Амплитуда движения поршня:')
  39.  
  40.  
  41. def setper(evt): # установление периода
  42. period = perslider.GetValue()
  43.  
  44. perslider = wx.Slider(p, pos=(win_width - 270, 230), size=(270, 20), minValue=1, maxValue=50)
  45. perslider.Bind(wx.EVT_SCROLL, setper)
  46.  
  47. wx.StaticText(p, pos=(win_width - 270, 200), label='Период движения поршня:')
  48.  
  49. def setnum(evt): # установление числа атомов
  50. global Natoms1
  51. Natoms1 = 10 + numslider.GetValue() // 20
  52.  
  53. numslider = wx.Slider(p, pos=(win_width - 270, 290), size=(270, 20), minValue=1, maxValue=2000)
  54. numslider.Bind(wx.EVT_SCROLL, setnum)
  55. wx.StaticText(p, pos=(win_width - 270, 260), label='Число атомов:')
  56.  
  57. def setmass(evt): # установление массы
  58. global mass1
  59. mass1 = mass * (massslider.GetValue() + 250) / 500
  60.  
  61. massslider = wx.Slider(p, pos=(win_width - 270, 350), size=(270, 20), minValue=1, maxValue=5000)
  62. massslider.Bind(wx.EVT_SCROLL, setmass)
  63. wx.StaticText(p, pos=(win_width - 270, 320), label='Масса атома:')
  64.  
  65. def setrat(evt): # установление размера атомов
  66. Ratom = ratslider.GetValue()
  67.  
  68. ratlslider = wx.Slider(p, pos=(win_width - 270, 410), size=(270, 20), minValue=0, maxValue=500)
  69. ratlslider.Bind(wx.EVT_SCROLL, setrat)
  70. wx.StaticText(p, pos=(win_width - 270, 380), label='Размер атома:')
  71.  
  72. def settemp(evt): # установление температуры
  73. T = tempslider.GetValue()
  74. tempslider = wx.Slider(p, pos=(win_width - 270, 470), size=(270, 20), minValue=1, maxValue=2000)
  75. tempslider.Bind(wx.EVT_SCROLL, settemp)
  76. wx.StaticText(p, pos=(win_width - 270, 440), label='Температура:')
  77.  
  78. def leave(evt): # выход из программы
  79. global still_working
  80. still_working = 1
  81. exit_program = wx.Button(p, label='ВЫХОД', pos=(win_width - 135, win_height - 50), size=(135, 50))
  82. exit_program.Bind(wx.EVT_BUTTON, leave)
  83. start = 0
  84.  
  85. def press_start(evt): # реакция на нажатие кнопки "старт"
  86. global start
  87. start = 1
  88. start_button = wx.Button(p, label='СТАРТ', pos=(win_width - 270, win_height - 50), size=(135, 50))
  89. start_button.Bind(wx.EVT_BUTTON, press_start)
  90. offset = 20
  91. disp = display(window=w, x=offset, y=offset, forward=vector(0, -0.3, -1),
  92. range=1.5,
  93. width=w.width / 3 - 2 * offset, height=w.height - 2 * offset)
  94. time = 0 # время, чтобы считать скорость поршня
  95.  
  96. def speed(time):
  97. if (time % 100 < 50):
  98. return sqrt(3 * 4E-3 / 6E23 * k * 300) / (5 * 4E-3 / 6E23)
  99. else:
  100. return -sqrt(3 * 4E-3 / 6E23 * k * 300) / (5 * 4E-3 / 6E23)
  101.  
  102.  
  103. L = 1 # container is a cube L on a side
  104. gray = color.gray(0.7) # color of edges of container
  105. d = L / 2 + Ratom # half of cylinder's height
  106. topborder = d
  107. cylindertop = cylinder(pos=(0, d, 0), axis=(0, -d / 50, 0), radius=d)
  108. ringtop = ring(pos=(0, d, 0), axis=(0, -d, 0), radius=d,
  109. thickness=0.005)
  110. ringbottom = ring(pos=(0, -d, 0), axis=(0, -d, 0), radius=d,
  111. thickness=0.005)
  112. body = cylinder(pos=(0, -d, 0), axis=(0, 2 * d, 0), radius=d,
  113. opacity=0.2)
  114. Atoms = [] # spheres
  115. p = [] # momentums (vectors)
  116. apos = [] # positions (vectors)
  117. pavg = sqrt(3 * mass * k * T) # average kinetic energy p**2/(2mass) = (3/2)kT
  118. # uniform particle distribution
  119. while (start == 0):
  120. if still_working == 1:
  121. exit()
  122. sleep(1)
  123. mass = mass1
  124. Natoms = Natoms1
  125.  
  126. for i in range(Natoms):
  127. qq = 2 * pi * random.random()
  128. x = sqrt(random.random()) * L * cos(qq) / 2
  129. y = L * random.random() - L / 2
  130. z = sqrt(random.random()) * L * sin(qq) / 2
  131. if i == 0:
  132. # particle with a trace
  133. Atoms.append(sphere(pos=vector(x, y, z), radius=Ratom,
  134. color=color.cyan, make_trail=True, retain=100,
  135. trail_radius=0.3 * Ratom))
  136. else:
  137. Atoms.append(sphere(pos=vector(x, y, z), radius=Ratom,
  138. color=gray))
  139. apos.append(vector(x, y, z))
  140. theta = pi * random.random()
  141. phi = 2 * pi * random.random()
  142. px = pavg * sin(theta) * cos(phi)
  143. py = pavg * sin(theta) * sin(phi)
  144. pz = pavg * cos(theta)
  145. p.append(vector(px, py, pz))
  146. # temperature graph
  147. g1 = gdisplay(window=w, x=w.width / 3, y=offset,
  148. width=w.width / 3, height=w.height / 2)
  149. graph_temp = gcurve(gdisplay=g1, color=color.cyan)
  150. deltav = 100 # histogram bar width
  151. g2 = gdisplay(window=w, x=w.width / 3, y=2 * offset + w.height / 2,
  152. width=w.width / 3, height=w.height / 2,
  153. xmax=3000, ymax=Natoms * deltav / 1000)
  154. """
  155. g2 = gdisplay(window = w, x = w.width / 3, y = 2 * offset + w.height / 2,
  156. width = w.width / 3, height = w.height / 2)
  157. """
  158. # theoretical prediction
  159. theory_speed = gcurve(gdisplay=g2, color=color.cyan)
  160. dv = 10
  161. for v in range(0, 3001 + dv, dv):
  162. theory_speed.plot(pos=(v, (deltav / dv) * Natoms *
  163. 4 * pi * ((mass / (2 * pi * k * T)) ** 1.5) *
  164. exp(-0.5 * mass * (v ** 2) / (k * T)) * (v ** 2) * dv))
  165. # histogram
  166. hist_speed = ghistogram(gdisplay=g2, bins=arange(0, 3000, 100),
  167. color=color.red, accumulate=True, average=True)
  168. speed_data = [] # histogram data
  169. for i in range(Natoms):
  170. speed_data.append(mag(p[i]) / mass)
  171. def checkCollisions():
  172. hitlist = []
  173. r2 = 2 * Ratom
  174. for i in range(Natoms):
  175. for j in range(i):
  176. dr = apos[i] - apos[j]
  177. if dr.mag < r2:
  178. hitlist.append([i, j])
  179. return hitlist
  180. while (still_working == 0):
  181. rate(100)
  182. sp = speed(time)
  183. cylindertop.pos.y -= sp * dt
  184. time += 1
  185. for i in range(Natoms):
  186. Atoms[i].pos = apos[i] = apos[i] + (p[i] / mass) * dt
  187. speed_data[i] = mag(p[i]) / mass
  188. hist_speed.plot(data=speed_data)
  189. total_momentum = 0
  190. v_sum = 0
  191. for i in range(Natoms):
  192. total_momentum += mag2(p[i])
  193. v_sum += sqrt(mag2(p[i])) / mass
  194. graph_temp.plot(pos=(time, total_momentum / (3 * k * mass) / Natoms))
  195. # graph_average_speed.plot(pos = (time, v_sum / Natoms))
  196. # cредняя скорость
  197. hitlist = checkCollisions()
  198. for ij in hitlist:
  199. i = ij[0]
  200. j = ij[1]
  201. ptot = p[i] + p[j]
  202. posi = apos[i]
  203. posj = apos[j]
  204. vi = p[i] / mass
  205. vj = p[j] / mass
  206. vrel = vj - vi
  207. a = vrel.mag2
  208. if a == 0: # exactly same velocities
  209. continue
  210. rrel = posi - posj
  211. if rrel.mag > Ratom: # one atom went all the way through another
  212. continue
  213. # theta is the angle between vrel and rrel:
  214. dx = dot(rrel, norm(vrel)) # rrel.mag*cos(theta)
  215. dy = cross(rrel, norm(vrel)).mag # rrel.mag*sin(theta)
  216. # alpha is the angle of the triangle composed of rrel, path of atom j, and a line
  217. # from the center of atom i to the center of atom j where atome j hits atom i:
  218. alpha = asin(dy / (2 * Ratom))
  219. d = (2 * Ratom) * cos(alpha) - dx # distance traveled into the atom from first contact
  220. deltat = d / vrel.mag # time spent moving from first contact to position inside atom
  221. posi = posi - vi * deltat # back up to contact configuration
  222. posj = posj - vj * deltat
  223. mtot = 2 * mass
  224. pcmi = p[i] - ptot * mass / mtot # transform momenta to cm frame
  225. pcmj = p[j] - ptot * mass / mtot
  226. rrel = norm(rrel)
  227. pcmi = pcmi - 2 * pcmi.dot(rrel) * rrel # bounce in cm frame
  228. pcmj = pcmj - 2 * pcmj.dot(rrel) * rrel
  229. p[i] = pcmi + ptot * mass / mtot # transform momenta back to lab frame
  230. p[j] = pcmj + ptot * mass / mtot
  231. apos[i] = posi + (p[i] / mass) * deltat # move forward deltat in time
  232. apos[j] = posj + (p[j] / mass) * deltat
  233. # collisions with walls
  234. for i in range(Natoms):
  235. # проекция радиус-вектора на плоскость
  236. loc = vector(apos[i])
  237. loc.y = 0
  238. # вылет за боковую стенку (цилиндр радиуса L / 2 + Ratom)
  239. if (mag(loc) > L / 2):
  240. # проекция импульса на плоскость
  241. proj_p = vector(p[i])
  242. proj_p.y = 0
  243. loc = norm(loc)
  244. # скалярное произведение нормированного радиус-вектора на импульс (все в проекции на плоскость)
  245. dotlp = dot(loc, proj_p)
  246. if dotlp > 0:
  247. p[i] -= 2 * dotlp * loc
  248. # dotlp < 0 - атом улетает от стенки
  249. # dotlp = 0 - атом летит вдоль стенки
  250. loc = apos[i]
  251. # вылет за торцы
  252. if loc.y < - L / 2:
  253. p[i].y = abs(p[i].y)
  254. if loc.y > cylindertop.pos.y - Ratom:
  255. v_otn = p[i].y / mass + sp
  256. if v_otn > 0:
  257. p[i].y = (- v_otn - sp) * mass
  258. print(0)
  259. exit()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement