def setQuaternion(self, Quaternion): """Set the orientation of the body in world coordinates (the display object is oriented to match).""" odelib.BaseBody.setQuaternion(self, Quaternion) # now set the orientation of the display frame # Rotating a point is q * (0,v) * q-1 # q-1 is w, -x, -y, -z assuming that q is a unit quaternion w1, x1, y1, z1 = Quaternion v1 = visual.vector(x1, y1, z1) w3 = w1 v3 = -v1 # First do the axis vector w2 = 0.0 v2 = visual.vector((1.0, 0.0, 0.0)) # This code is equivalent to a quaternion multiply: qR = q1 * q2 * q3 w12 = (w1 * w2) - visual.dot(v1, v2) v12 = (w1 * v2) + (w2 * v1) + visual.cross(v1, v2) wR = (w12 * w3) - visual.dot(v12, v3) vR = (w12 * v3) + (w3 * v12) + visual.cross(v12, v3) self._myFrame.axis = vR # Do it again for the up vector w2 = 0.0 v2 = visual.vector((0.0, 1.0, 0.0)) # This code is equivalent to a quaternion multiply: qR = q1 * q2 * q3 w12 = (w1 * w2) - visual.dot(v1, v2) v12 = (w1 * v2) + (w2 * v1) + visual.cross(v1, v2) wR = (w12 * w3) - visual.dot(v12, v3) vR = (w12 * v3) + (w3 * v12) + visual.cross(v12, v3) self._myFrame.up = vR
def drawCameraFrame(): # create frame and draw its contents global cam_box, cent_plane, cam_lab, cam_tri, range_lab, linelen, fwd_line global fwd_arrow, mouse_line, mouse_arrow, mouse_lab, fov, range_x, cam_dist, cam_frame global ray cam_frame = vs.frame( pos = vs.vector(0,2,2,), axis = (0,0,1)) # NB: contents are rel to this frame. start with camera looking "forward" # origin is at simulated scene.center fov = vs.pi/3.0 # 60 deg range_x = 6 # simulates scene.range.x cam_dist = range_x / vs.tan(fov/2.0) # distance between camera and center. ray = vs.vector(-20.0, 2.5, 3.0).norm() # (unit) direction of ray vector (arbitrary) # REL TO CAMERA FRAME cam_box = vs.box(frame=cam_frame, length=1.5, height=1, width=1.0, color=clr.blue, pos=(cam_dist,0,0)) # camera-box cent_plane = vs.box(frame=cam_frame, length=0.01, height=range_x*1.3, width=range_x*2, pos=(0,0,0), opacity=0.5 ) # central plane cam_lab = vs.label(frame=cam_frame, text= 'U', pos= (cam_dist,0,0), height= 9, xoffset= 6) cam_tri = vs.faces( frame=cam_frame, pos=[(0,0,0), (0,0,-range_x), (cam_dist,0,0)]) cam_tri.make_normals() cam_tri.make_twosided() range_lab = vs.label(frame=cam_frame, text= 'R', pos= (0, 0, -range_x), height= 9, xoffset= 6) linelen = scene_size + vs.mag( cam_frame.axis.norm()*cam_dist + cam_frame.pos) # len of lines from camera fwd_line = drawLine( vs.vector(cam_dist,0,0), linelen, vs.vector(-1,0,0)) fwd_arrow = vs.arrow(frame=cam_frame, axis=(-2,0,0), pos=(cam_dist, 0, 0), shaftwidth=0.08, color=clr.yellow) vs.label(frame=cam_frame, text='C', pos=(0,0,0), height=9, xoffset=6, color=clr.yellow) mouse_line = drawLine ( vs.vector(cam_dist,0,0), linelen, ray ) mouse_arrow = vs.arrow(frame=cam_frame, axis=ray*2, pos=(cam_dist,0,0), shaftwidth=0.08, color=clr.red) mouse_lab = vs.label(frame=cam_frame, text= 'M', height= 9, xoffset= 10, color=clr.red, pos= -ray*(cam_dist/vs.dot(ray,(1,0,0))) + (cam_dist,0,0))
def handleCollision(self, other): difference = other.p - self.p if mag(difference) < self.radius + other.radius: vrelative = other.v - self.v normal = norm(difference) vrn = dot(vrelative, normal) if vrn < 0: #Collision Detected! difference = norm(difference) #Compute magnitude of Impulse Imag = -(1 + restitution) * vrn / (1.0 / self.mass + 1.0 / other.mass) I = Imag * normal # convert to a vector #Apply impulse to both affected balls self.v -= I / self.mass other.v += I / other.mass
def draw_camera_frame(): """Create frame and draw its contents.""" global CAM_BOX, CENT_PLANE, CAM_LAB, CAN_TRI, RANGE_LAB, LINELEN, FWD_LINE global FWR_ARROW, MOUSE_LINE, MOUSE_ARROW, MOUSE_LAB, FOV, RANGE_X, CAM_DIST, CAM_FRAME global RAY CAM_FRAME = vs.frame(pos=vs.vector(0, 2, 2, ), axis=(0, 0, 1)) # NB: contents are rel to this frame. start with camera looking "forward" # origin is at simulated scene.center FOV = vs.pi/3.0 # 60 deg RANGE_X = 6 # simulates scene.range.x CAM_DIST = RANGE_X / vs.tan(FOV/2.0) # distance between camera and center. RAY = vs.vector(-20.0, 2.5, 3.0).norm() # (unit) direction of ray vector (arbitrary) # REL TO CAMERA FRAME CAM_BOX = vs.box(frame=CAM_FRAME, length=1.5, height=1, width=1.0, color=CLR.blue, pos=(CAM_DIST, 0, 0)) # camera-box CENT_PLANE = vs.box(frame=CAM_FRAME, length=0.01, height=RANGE_X*1.3, width=RANGE_X*2, pos=(0, 0, 0), opacity=0.5) # central plane CAM_LAB = vs.label(frame=CAM_FRAME, text='U', pos=(CAM_DIST, 0, 0), height=9, xoffset=6) CAN_TRI = vs.faces(frame=CAM_FRAME, pos=[ (0, 0, 0), (0, 0, -RANGE_X), (CAM_DIST, 0, 0)]) CAN_TRI.make_normals() CAN_TRI.make_twosided() RANGE_LAB = vs.label(frame=CAM_FRAME, text='R', pos=(0, 0, -RANGE_X), height=9, xoffset=6) LINELEN = SCENE_SIZE + vs.mag( CAM_FRAME.axis.norm()*CAM_DIST + CAM_FRAME.pos) # len of lines from camera FWD_LINE = draw_line(vs.vector(CAM_DIST, 0, 0), LINELEN, vs.vector(-1, 0, 0)) FWR_ARROW = vs.arrow(frame=CAM_FRAME, axis=(-2, 0, 0), pos=(CAM_DIST, 0, 0), shaftwidth=0.08, color=CLR.yellow) vs.label(frame=CAM_FRAME, text='C', pos=(0, 0, 0), height=9, xoffset=6, color=CLR.yellow) MOUSE_LINE = draw_line(vs.vector(CAM_DIST, 0, 0), LINELEN, RAY) MOUSE_ARROW = vs.arrow(frame=CAM_FRAME, axis=RAY*2, pos=(CAM_DIST, 0, 0), shaftwidth=0.08, color=CLR.red) MOUSE_LAB = vs.label( frame=CAM_FRAME, text='M', height=9, xoffset=10, color=CLR.red, pos=-RAY*(CAM_DIST/vs.dot(RAY, (1, 0, 0))) + (CAM_DIST, 0, 0))
elif propulsion['type'] == HORIZONTAL: ortho_vector = rocket_pos / rocket_pos.mag direction = vector(ortho_vector.y, -ortho_vector.x) else: raise SystemError force = propulsion['magnitude'] * direction f_propulsion += force else: if not notified and time > propulsion['from']: print("PRopulsion stopped") notified = True # plt.pause(0.02) try: theta = acos( dot(rocket_vel, rocket_pos) / rocket_vel.mag / rocket_pos.mag) / pi except: pass if time > TIME_SKIP: print( "t= {0}, v={1:.0f}, h={2:.2f}, theta={3:.2f}, g={4:.2f}, E={5:1.1e}" .format(time, rocket_vel.mag - 241, rocket_pos.mag - RADIUS_OF_MARS, theta, f_gravity.mag, get_total_energy())) if rocket_pos.mag < RADIUS_OF_MARS: print("Rocket landed on ground with velocity: {0:.0f}".format( rocket_vel.mag)) print("Total energy used: {}".format(get_total_energy())) with open("energy-used.tmp", "a") as f:
if Q_PY: GEARING = 4 else: GEARING = 1 CAM_DIST = CAM_DIST + (MOUSE_CHANGE.x + MOUSE_CHANGE.y + MOUSE_CHANGE.z)*GEARING if CAM_DIST <= 0: CAM_DIST = 0.001 # allow only positive LIMIT = SCENE_SIZE*2 if CAM_DIST > LIMIT: CAM_DIST = LIMIT # limit size redraw_lines() CAM_BOX.pos = (CAM_DIST, 0, 0) CAM_LAB.pos = (CAM_DIST, 0, 0) FWR_ARROW.pos = (CAM_DIST, 0, 0) MOUSE_ARROW.pos = (CAM_DIST, 0, 0) MOUSE_LAB.pos = -RAY*(CAM_DIST/vs.dot(RAY, (1, 0, 0))) + (CAM_DIST, 0, 0) RANGE_X = CAM_DIST * vs.tan(FOV/2.0) CENT_PLANE.width = RANGE_X*2 CENT_PLANE.height = RANGE_X*4.0/3 redraw_tri() # redraw the camera triangle RANGE_LAB.pos = (0, 0, -RANGE_X) MODE_LAB.SetLabel('scene.range:\n' + format(RANGE_X, "9.3")) if not Q_PY: VSS.range = RANGE_X elif MODE == 'v': # demonstrate altering scene.fov CAM_DIST = CAM_DIST + (MOUSE_CHANGE.x + MOUSE_CHANGE.y + MOUSE_CHANGE.z)*4 if CAM_DIST <= 0: CAM_DIST = 0.001 # allow only positive RAY = (MOUSE_LAB.pos - (CAM_DIST, 0, 0)).norm() redraw_lines()
def proj(a,b): '''Projects the vector a along the direction of b.''' return vector(dot(a, norm(b)) * norm(b))
def dot(self, other): return dot(self.v, other.v)
mode_lab.SetLabel('scene.forward:\n' + str2( - cam_frame.axis)) if not qPy: vss.forward = - cam_frame.axis elif mode == 'r': # demonstrate altering scene.range. Alters size of camera triangle. if qPy: gearing = 4 else: gearing = 1 cam_dist = cam_dist + (mouse_change.x + mouse_change.y + mouse_change.z)*gearing if cam_dist <= 0: cam_dist = 0.001 # allow only positive limit = scene_size*2 if cam_dist > limit: cam_dist = limit # limit size reDrawLines() cam_box.pos = (cam_dist,0,0) cam_lab.pos = (cam_dist,0,0) fwd_arrow.pos = (cam_dist,0,0) mouse_arrow.pos = (cam_dist,0,0) mouse_lab.pos = -ray*(cam_dist/vs.dot(ray,(1,0,0))) + (cam_dist,0,0) range_x = cam_dist * vs.tan(fov/2.0) cent_plane.width = range_x*2 cent_plane.height = range_x*4.0/3 reDrawTri() # redraw the camera triangle range_lab.pos= (0,0,-range_x) mode_lab.SetLabel( 'scene.range:\n' + format( range_x, "9.3")) if not qPy: vss.range = range_x elif mode == 'v': # demonstrate altering scene.fov cam_dist = cam_dist + (mouse_change.x + mouse_change.y + mouse_change.z)*4 if cam_dist <= 0: cam_dist = 0.001 # allow only positive ray = (mouse_lab.pos - (cam_dist, 0,0)).norm() reDrawLines() cam_box.pos = (cam_dist,0,0) cam_lab.pos = (cam_dist,0,0)
def drawCameraFrame(): # create frame and draw its contents global cam_box, cent_plane, cam_lab, cam_tri, range_lab, linelen, fwd_line global fwd_arrow, mouse_line, mouse_arrow, mouse_lab, fov, range_x, cam_dist, cam_frame global ray cam_frame = vs.frame(pos=vs.vector( 0, 2, 2, ), axis=(0, 0, 1)) # NB: contents are rel to this frame. start with camera looking "forward" # origin is at simulated scene.center fov = vs.pi / 3.0 # 60 deg range_x = 6 # simulates scene.range.x cam_dist = range_x / vs.tan( fov / 2.0) # distance between camera and center. ray = vs.vector(-20.0, 2.5, 3.0).norm() # (unit) direction of ray vector (arbitrary) # REL TO CAMERA FRAME cam_box = vs.box(frame=cam_frame, length=1.5, height=1, width=1.0, color=clr.blue, pos=(cam_dist, 0, 0)) # camera-box cent_plane = vs.box(frame=cam_frame, length=0.01, height=range_x * 1.3, width=range_x * 2, pos=(0, 0, 0), opacity=0.5) # central plane cam_lab = vs.label(frame=cam_frame, text='U', pos=(cam_dist, 0, 0), height=9, xoffset=6) cam_tri = vs.faces(frame=cam_frame, pos=[(0, 0, 0), (0, 0, -range_x), (cam_dist, 0, 0)]) cam_tri.make_normals() cam_tri.make_twosided() range_lab = vs.label(frame=cam_frame, text='R', pos=(0, 0, -range_x), height=9, xoffset=6) linelen = scene_size + vs.mag(cam_frame.axis.norm() * cam_dist + cam_frame.pos) # len of lines from camera fwd_line = drawLine(vs.vector(cam_dist, 0, 0), linelen, vs.vector(-1, 0, 0)) fwd_arrow = vs.arrow(frame=cam_frame, axis=(-2, 0, 0), pos=(cam_dist, 0, 0), shaftwidth=0.08, color=clr.yellow) vs.label(frame=cam_frame, text='C', pos=(0, 0, 0), height=9, xoffset=6, color=clr.yellow) mouse_line = drawLine(vs.vector(cam_dist, 0, 0), linelen, ray) mouse_arrow = vs.arrow(frame=cam_frame, axis=ray * 2, pos=(cam_dist, 0, 0), shaftwidth=0.08, color=clr.red) mouse_lab = vs.label(frame=cam_frame, text='M', height=9, xoffset=10, color=clr.red, pos=-ray * (cam_dist / vs.dot(ray, (1, 0, 0))) + (cam_dist, 0, 0))
if not qPy: vss.forward = -cam_frame.axis elif mode == 'r': # demonstrate altering scene.range. Alters size of camera triangle. if qPy: gearing = 4 else: gearing = 1 cam_dist = cam_dist + (mouse_change.x + mouse_change.y + mouse_change.z) * gearing if cam_dist <= 0: cam_dist = 0.001 # allow only positive limit = scene_size * 2 if cam_dist > limit: cam_dist = limit # limit size reDrawLines() cam_box.pos = (cam_dist, 0, 0) cam_lab.pos = (cam_dist, 0, 0) fwd_arrow.pos = (cam_dist, 0, 0) mouse_arrow.pos = (cam_dist, 0, 0) mouse_lab.pos = -ray * (cam_dist / vs.dot(ray, (1, 0, 0))) + (cam_dist, 0, 0) range_x = cam_dist * vs.tan(fov / 2.0) cent_plane.width = range_x * 2 cent_plane.height = range_x * 4.0 / 3 reDrawTri() # redraw the camera triangle range_lab.pos = (0, 0, -range_x) mode_lab.SetLabel('scene.range:\n' + format(range_x, "9.3")) if not qPy: vss.range = range_x elif mode == 'v': # demonstrate altering scene.fov cam_dist = cam_dist + (mouse_change.x + mouse_change.y + mouse_change.z) * 4 if cam_dist <= 0: cam_dist = 0.001 # allow only positive ray = (mouse_lab.pos - (cam_dist, 0, 0)).norm() reDrawLines()
# For planet data ptf=int(raw_input("Which planet are you interested in (Mercury: 0,..., Pluto: 7) ")) # Planet to find (0: Mercury,..., 8 for Pluto) times=float(raw_input("How many data points do you want for the planet: ")) # Number of times data are taken timc=0 # Counter year=[] # List of orbital periods per=[] # List of perihelion distances aph=[] # List of aphelion distances pos0=v.vector(planet[ptf].pos) # Initial position of chosen planet pe1=v.mag(pos0) # Variable for perihilion distance ap1=v.mag(pos0) # Variable for aphilion distance dirc0=v.dot(pos0,pos0) # Dot product (changes sign when angle crosses pi/2: keeping track of revolutions) t_init=0 # Initial time for starting calculation (when the planet is perpendicular to initial position vector for the first time) # For moon data timoon=float(raw_input("How many data points do you want for the moon: ")) # Number of times moon data are taken #mtf=int(raw_input("Which moon are you interested in (Moon: 0, Deimos: 1) ")) # Moon to find mtf=9 # Moon to find: only one anyway timcm=0 # Counter month=[] # List of lunar orbital periods posm0=planet[mtf].pos-planet[planet[mtf].mom].pos # Initial position of moon relative to its planet dircm0=v.dot(posm0,posm0) # Dot product tm_init=0 # Initial time for taking moon data peg=[] # List of prigee distances apg=[] # List of apogee distance
def proj(a, b): '''Projects the vector a along the direction of b.''' return vector(dot(a, norm(b)) * norm(b))
def Simulation(): config.Atoms = [] # spheres p = [] # momentums (vectors) apos = [] # positions (vectors) ampl = 0 #амплитуда движения period = 5 k = 1.4E-23 # Boltzmann constant R = 8.3 dt = 1E-5 time = 0 def checkCollisions(Natoms, Ratom): hitlist = [] r2 = 2 * Ratom for i in range(Natoms): for j in range(i): dr = apos[i] - apos[j] if dr.mag < r2: hitlist.append([i, j]) return hitlist def speed(time, piston_mode, period, ampl, temp): if (piston_mode == 0): return 0 if (piston_mode == 1): return ampl / 10 * 3 * sin(time / period * 2 * pi) * sqrt( 3 * config.mass * k * temp) / (5 * config.mass) / period * 100 if (piston_mode == 2): if (time % period < period // 2): return 1.5 * ampl / 10 * sqrt(3 * config.mass * k * temp) / ( 5 * config.mass) / period * 100 else: return -1.5 * ampl / 10 * sqrt(3 * config.mass * k * temp) / ( 5 * config.mass) / period * 100 if (piston_mode == 3): if (time % period < period // 5): return 5 * ampl / 10 * sqrt(3 * config.mass * k * temp) / ( 5 * config.mass) / period * 100 else: return -5 / 4 * ampl / 10 * sqrt( 3 * config.mass * k * temp) / (5 * config.mass) / period * 100 if (piston_mode == 4): if (time % period < 4 * period // 5): return 5 / 4 * ampl / 10 * sqrt(3 * config.mass * k * temp) / ( 5 * config.mass) / period * 100 else: return -5 * ampl / 10 * sqrt(3 * config.mass * k * temp) / ( 5 * config.mass) / period * 100 width, height = config.w.win.GetSize() offset = config.w.dheight deltav = 100 # histogram bar width disp = display( window=config.w, x=offset, y=offset, forward=vector(0, -0.05, -1), range=1, # userspin = False, width=width / 3, height=height) g1 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=2 * offset, background=color.white, xtitle='t', ytitle='v', foreground=color.black, width=width / 3, height=height / 2 - 2 * offset) g2 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=height / 2 + offset, background=color.white, foreground=color.black, width=width / 3, height=height / 2 - 2 * offset) # adding empty dots to draw axis graph_average_speed = gcurve(gdisplay=g1, color=color.white) graph_average_speed.plot(pos=(3000, 1500)) graph_temp = gcurve(gdisplay=g2, color=color.white) graph_temp.plot(pos=(3000, config.Natoms * deltav / 1000)) speed_text = wx.StaticText(config.w.panel, pos=(width / 3 + 2 * offset, offset), label="Средняя скорость") graph_text = wx.StaticText(config.w.panel, pos=(width / 3 + 2 * offset, height / 2), label="") L = 1 # container is a cube L on a side d = L / 2 + config.Ratom # half of cylinder's height topborder = d gray = color.gray(0.7) # color of edges of container # cylinder drawing cylindertop = cylinder(pos=(0, d - 0.001, 0), axis=(0, 0.005, 0), radius=d) ringtop = ring(pos=(0, d, 0), axis=(0, -d, 0), radius=d, thickness=0.005) ringbottom = ring(pos=(0, -d, 0), axis=(0, -d, 0), radius=d, thickness=0.005) body = cylinder(pos=(0, -d, 0), axis=(0, 2 * d, 0), radius=d, opacity=0.2) # body_tmp = cylinder(pos = (0, d, 0), axis = (0, 2 * d, 0), radius = d + 0.1, color = (0, 0, 0)) # ceil = box(pos = (0, d, 0), length = 5, height = 0.005, width = 5, color = (0, 0, 0)) # floor = box(pos = (0, -d, 0), length = 100, height = 0.005, width = 100, color = (0, 0, 0)) # left = box(pos = (d + 0.005, 0, 0), axis = (0, 1, 0), length = 100, height = 0.005, width = 100, color = (0, 0, 0)) # right = box(pos = (-d - 0.005, 0, 0), axis = (0, 1, 0), length = 100, height = 0.005, width = 100, color = (0, 0, 0)) # uniform particle distribution for i in range(config.Natoms): qq = 2 * pi * random.random() x = sqrt(random.random()) * L * cos(qq) / 2 y = L * random.random() - L / 2 z = sqrt(random.random()) * L * sin(qq) / 2 if i == 0: # particle with a trace config.Atoms.append( sphere(pos=vector(x, y, z), radius=config.Ratom, color=color.cyan, make_trail=False, retain=100, trail_radius=0.3 * config.Ratom)) else: config.Atoms.append( sphere(pos=vector(x, y, z), radius=config.Ratom, color=gray)) apos.append(vector(x, y, z)) # waiting to start, adjusting everything according to changing variables """WAITING TO START""" last_Natoms = config.Natoms last_Ratom = config.Ratom while config.start == 0: if config.menu_switch == 0: disp.delete() g1.display.delete() g2.display.delete() graph_text.Destroy() speed_text.Destroy() return if config.Natoms > last_Natoms: for i in range(config.Natoms - last_Natoms): qq = 2 * pi * random.random() x = sqrt(random.random()) * L * cos(qq) / 2 y = L * random.random() - L / 2 z = sqrt(random.random()) * L * sin(qq) / 2 if last_Natoms == 0: # particle with a trace config.Atoms.append( sphere(pos=vector(x, y, z), radius=config.Ratom, color=color.cyan, make_trail=False, retain=100, trail_radius=0.3 * config.Ratom)) else: config.Atoms.append( sphere(pos=vector(x, y, z), radius=config.Ratom, color=gray)) apos.append(vector(x, y, z)) last_Natoms = config.Natoms elif config.Natoms < last_Natoms: for i in range(last_Natoms - config.Natoms): config.Atoms.pop().visible = False apos.pop() last_Natoms = config.Natoms if last_Ratom != config.Ratom: for i in range(last_Natoms): config.Atoms[i].radius = config.Ratom last_Ratom = config.Ratom if config.model == 0: if config.piston_mode >= 1: graph_text.SetLabel("Температура") else: graph_text.SetLabel("Распределение скоростей частиц") sleep(0.1) # freezed all variables, ready to start last_T = config.T last_ampl = config.ampl last_period = config.period last_piston_mode = config.piston_mode last_model = config.model pavg = sqrt(3 * config.mass * k * last_T) # average kinetic energy p**2/(2config.mass) = (3/2)kT for i in range(last_Natoms): theta = pi * random.random() phi = 2 * pi * random.random() px = pavg * sin(theta) * cos(phi) py = pavg * sin(theta) * sin(phi) pz = pavg * cos(theta) p.append(vector(px, py, pz)) if last_model == 1: disp.delete() unavail = wx.StaticText( config.w.panel, style=wx.ALIGN_CENTRE_HORIZONTAL, label="Отображение модели недоступно в режиме статистики", pos=(offset, height / 2 - offset)) unavail.Wrap(width / 3) last_period = last_period / 10 last_piston_mode += 1 graph_text.SetLabel("Температура") """ DRAW GRAPHS """ g1.display.delete() g2.display.delete() if last_piston_mode == 0: g1 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=2 * offset, background=color.white, xtitle='t', ytitle='v', foreground=color.black, width=width / 3, height=height / 2 - 2 * offset, ymin=0.7 * pavg / config.mass, ymax=1.3 * pavg / config.mass) g2 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=height / 2 + offset, background=color.white, foreground=color.black, xtitle='v', ytitle='Frequency', width=width / 3, height=height / 2 - 2 * offset, xmax=3000 / 300 * last_T, ymax=last_Natoms * deltav / 1000) else: g1 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=2 * offset, background=color.white, xtitle='t', ytitle='v', foreground=color.black, width=width / 3, height=height / 2 - 2 * offset) g2 = gdisplay(window=config.w, x=width / 3 + 2 * offset, y=height / 2 + offset, background=color.white, xtitle='t', ytitle='T', foreground=color.black, width=width / 3, height=height / 2 - 2 * offset) graph_average_speed = gcurve(gdisplay=g1, color=color.black) if last_piston_mode: graph_temp = gcurve(gdisplay=g2, color=color.black) else: theory_speed = gcurve(gdisplay=g2, color=color.black) dv = 10 for v in range(0, int(3000 / 300 * last_T), dv): theory_speed.plot(pos=(v, (deltav / dv) * last_Natoms * 4 * pi * ((config.mass / (2 * pi * k * last_T))**1.5) * exp(-0.5 * config.mass * (v**2) / (k * last_T)) * (v**2) * dv)) hist_speed = ghistogram(gdisplay=g2, bins=arange(0, int(3000 / 300 * last_T), 100), color=color.red, accumulate=True, average=True) speed_data = [] # histogram data for i in range(last_Natoms): speed_data.append(pavg / config.mass) # speed_data.append(0) """ MAIN CYCLE """ while config.start: while config.pause: sleep(0.1) rate(100) sp = speed(time, last_piston_mode, last_period, last_ampl, 300) cylindertop.pos.y -= sp * dt time += 1 for i in range(last_Natoms): config.Atoms[i].pos = apos[i] = apos[i] + (p[i] / config.mass) * dt if last_piston_mode == 0: speed_data[i] = mag(p[i]) / config.mass total_momentum = 0 v_sum = 0 for i in range(last_Natoms): total_momentum += mag2(p[i]) v_sum += sqrt(mag2(p[i])) / config.mass graph_average_speed.plot(pos=(time, v_sum / last_Natoms)) if last_piston_mode: graph_temp.plot(pos=(time, total_momentum / (3 * k * config.mass) / last_Natoms)) else: hist_speed.plot(data=speed_data) hitlist = checkCollisions(last_Natoms, last_Ratom) for ij in hitlist: i = ij[0] j = ij[1] ptot = p[i] + p[j] posi = apos[i] posj = apos[j] vi = p[i] / config.mass vj = p[j] / config.mass vrel = vj - vi a = vrel.mag2 if a == 0: # exactly same velocities continue rrel = posi - posj if rrel.mag > config.Ratom: # one atom went all the way through another continue # theta is the angle between vrel and rrel: dx = dot(rrel, norm(vrel)) # rrel.mag*cos(theta) dy = cross(rrel, norm(vrel)).mag # rrel.mag*sin(theta) # alpha is the angle of the triangle composed of rrel, path of atom j, and a line # from the center of atom i to the center of atom j where atome j hits atom i: alpha = asin(dy / (2 * config.Ratom)) d = (2 * config.Ratom) * cos( alpha ) - dx # distance traveled into the atom from first contact deltat = d / vrel.mag # time spent moving from first contact to position inside atom posi = posi - vi * deltat # back up to contact configuration posj = posj - vj * deltat mtot = 2 * config.mass pcmi = p[ i] - ptot * config.mass / mtot # transform momenta to cm frame pcmj = p[j] - ptot * config.mass / mtot rrel = norm(rrel) pcmi = pcmi - 2 * pcmi.dot(rrel) * rrel # bounce in cm frame pcmj = pcmj - 2 * pcmj.dot(rrel) * rrel p[i] = pcmi + ptot * config.mass / mtot # transform momenta back to lab frame p[j] = pcmj + ptot * config.mass / mtot apos[i] = posi + ( p[i] / config.mass) * deltat # move forward deltat in time apos[j] = posj + (p[j] / config.mass) * deltat # collisions with walls for i in range(last_Natoms): # проекция радиус-вектора на плоскость loc = vector(apos[i]) loc.y = 0 # вылет за боковую стенку (цилиндр радиуса L / 2 + config.Ratom) if (mag(loc) > L / 2 + 0.01 - last_Ratom + sqrt(p[i].x**2 + p[i].z**2) / config.mass * dt): # проекция импульса на плоскость proj_p = vector(p[i]) proj_p.y = 0 loc = norm(loc) # скалярное произведение нормированного радиус-вектора на импульс (все в проекции на плоскость) dotlp = dot(loc, proj_p) if dotlp > 0: p[i] -= 2 * dotlp * loc # dotlp < 0 - атом улетает от стенки # dotlp = 0 - атом летит вдоль стенки loc = apos[i] # вылет за торцы if loc.y + p[i].y / config.mass * dt < -L / 2 - 0.01 + last_Ratom: p[i].y = abs(p[i].y) if loc.y + p[ i].y / config.mass * dt > cylindertop.pos.y - last_Ratom: v_otn = p[i].y / config.mass + sp if v_otn > 0: p[i].y = (-v_otn - sp) * config.mass # type here if last_model == 0: disp.delete() else: unavail.Destroy() g1.display.delete() g2.display.delete() graph_text.Destroy() speed_text.Destroy()