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 GetElementWorldLocation(self, ElementKey): """Returns the location of the specified element in world coordinates.""" assert ElementKey in self._elementDict self._elementDict.get(ElementKey).SetVisible(isVisible) localPos = self.GetElement(ElementKey).pos xAxis = visual.norm(self._myFrame.axis) zAxis = visual.norm(visual.cross(self._myFrame.axis, self._myFrame.up)) yAxis = visual.norm(visual.cross(z_axis, x_axis)) worldPos = self._myFrame.pos + (localPos.x * xAxis) + (localPos.y * yAxis) + (localPos.z * zAxis) return worldPos
def GetElementWorldLocation(self, ElementKey): """Returns the location of the specified element in world coordinates.""" assert ElementKey in self._elementDict self._elementDict.get(ElementKey).SetVisible(isVisible) localPos = self.GetElement(ElementKey).pos xAxis = visual.norm(self._myFrame.axis) zAxis = visual.norm(visual.cross(self._myFrame.axis, self._myFrame.up)) yAxis = visual.norm(visual.cross(z_axis, x_axis)) worldPos = self._myFrame.pos + (localPos.x * xAxis) + ( localPos.y * yAxis) + (localPos.z * zAxis) return worldPos
def build(self, Verticies, Faces, Colors=None, Normals=None, IsSoft=False): """Build a displayable tri-mesh object. This is an overload of ode.TriMeshData.build().""" # Fill out our TriMeshData object properties by calling the parent ode.TriMeshData.build(self, Verticies, Faces) self._verticies = [] self._colors = [] self._normals = [] # Expand the mesh to make it suitable for use with Visual for face in Faces: for index, vertex in enumerate(face): self._verticies.append(Verticies[vertex]) if Colors is not None: self._colors.append(Colors[vertex]) else: # Assign a default self._colors.append(visual.color.white) if Normals is not None: self._normals.append(Normals[vertex]) else: # Compute the normals using cross products normal = visual.norm(visual.cross(Verticies[face[index]], Verticies[face[(index + 1) % 3]])) self._normals.append(normal) if IsSoft: # Need to go back and average normals -- implement later pass
def build(self, Verticies, Faces, Colors=None, Normals=None, IsSoft=False): """Build a displayable tri-mesh object. This is an overload of ode.TriMeshData.build().""" # Fill out our TriMeshData object properties by calling the parent ode.TriMeshData.build(self, Verticies, Faces) self._verticies = [] self._colors = [] self._normals = [] # Expand the mesh to make it suitable for use with Visual for face in Faces: for index, vertex in enumerate(face): self._verticies.append(Verticies[vertex]) if Colors is not None: self._colors.append(Colors[vertex]) else: # Assign a default self._colors.append(visual.color.white) if Normals is not None: self._normals.append(Normals[vertex]) else: # Compute the normals using cross products normal = visual.norm( visual.cross(Verticies[face[index]], Verticies[face[(index + 1) % 3]])) self._normals.append(normal) if IsSoft: # Need to go back and average normals -- implement later pass
def golfball_step(t,x,y,z,vx,vy,vz,m,g,B2,S0,w,dt,w_vector,v_vector): t = t+dt x = x + vx*dt y = y + vy*dt z = z + vz*dt FM = (S0*visual.cross(w_vector,v_vector))/m #vz = vz + (Fmz/m)*dt vz = vz + FM.z*dt#((S0*w*vx)*dt) v = math.sqrt((vx**2)+(vy**2)+(vz**2)) vx = vx - (((B2*v*vx)/m)*dt) + FM.x*dt#((S0*w*vy)*dt) vy = vy - g*dt - (((B2*v*vy)/m)*dt) + FM.y*dt#((S0*w*vz)*dt) return t,x,y,z,vx,vy,vz
def go(animate=True): # default: True r, v = np.array([0.4667, 0.0]), np.array([0.0, 8.198]) # init r, v t, h, ta, angle = 0.0, 0.002, [], [] w = 1.0 / vp.mag(r) # $W_0=\Omega(r)$ if (animate): planet, info, RLvec = set_scene(r) while t < 100: # run for 100 years L = vp.cross(r, v) # $\vec{L}/m=\vec{r}\times \vec{v}$ A = vp.cross(v, L) - GM * r / vp.mag(r) # scaled RL vec, ta.append(t) angle.append(np.arctan(A.y / A.x) * 180 * 3600 / np.pi) # arcseconds if (animate): vp.rate(100) planet.pos = r # move planet RLvec.axis, RLvec.length = A, .25 # update RL vec info.text = 'Angle": %8.2f' % (angle[-1]) # angle info r, v, t, w = ode.leapfrog_tt(mercury, r, v, t, w, h) plt.figure() # make plot plt.plot(ta, angle) plt.xlabel('Time (year)'), plt.ylabel('Precession (arcsec)') plt.show()
def go(animate = True): # default: True r, v = np.array([0.4667, 0.0]), np.array([0.0, 8.198]) # init r, v t, h, ta, angle = 0.0, 0.002, [], [] w = 1.0/vp.mag(r) # $W_0=\Omega(r)$ if (animate): planet, info, RLvec = set_scene(r) while t<100: # run for 100 years L = vp.cross(r, v) # $\vec{L}/m=\vec{r}\times \vec{v}$ A = vp.cross(v, L) - GM*r/vp.mag(r) # scaled RL vec, ta.append(t) angle.append(np.arctan(A.y/A.x)*180*3600/np.pi) # arcseconds if (animate): vp.rate(100) planet.pos = r # move planet RLvec.axis, RLvec.length = A, .25 # update RL vec info.text='Angle": %8.2f' %(angle[-1]) # angle info r, v, t, w = ode.leapfrog_tt(mercury, r, v, t, w, h) plt.figure() # make plot plt.plot(ta, angle) plt.xlabel('Time (year)'), plt.ylabel('Precession (arcsec)') plt.show()
def vs_loop(): #pan_inc = 0.25 #zoom_inc = array((0.25,0.25,0.25)) pan_inc = 0.25 zoom_inc = array((0.05, 0.05, 0.05)) # for scene rotation with invariant light direction light_frame = vs.frame() for obj in vs.scene.lights: if isinstance(obj, vs.distant_light): obj.frame = light_frame # put distant lights in a frame prev_scene_forward = vs.vector( vs.scene.forward) # keep a copy of the old forward while True: if vs.scene.kb.keys: key = vs.scene.kb.getkey() if key == 'up': vs.scene.center = array(vs.scene.center) + array( (0, pan_inc, 0)) elif key == 'down': vs.scene.center = array(vs.scene.center) + array( (0, -pan_inc, 0)) elif key == 'left': vs.scene.center = array(vs.scene.center) + array( (-pan_inc, 0, 0)) elif key == 'right': vs.scene.center = array(vs.scene.center) + array( (pan_inc, 0, 0)) elif key == 'shift+up': vs.scene.range -= zoom_inc elif key == 'shift+down': vs.scene.range += zoom_inc if vs.scene.forward != prev_scene_forward: new = vs.scene.forward axis = vs.cross(prev_scene_forward, new) angle = new.diff_angle(prev_scene_forward) light_frame.rotate(axis=axis, angle=angle) prev_scene_forward = vs.vector(new)
def ball_step(x,y,z,vx,vy,vz,g,ball,S0,w_vector,dt): v_vector = visual.vector(vx,vy,vz) #Defines velocity vector based on components FM = S0 * visual.cross(w_vector,v_vector) / ball.mass #Finds acceleration from Magnus Force x = x + vx*dt y = y + vy*dt #Alters the position z = z + vz*dt vz = vz + FM.z*dt #Changes vz based on the Magnus acceleration in the Z direction v = v_vector.mag #defines v as the magnitude of the velocity vector for use below vx = vx - (((ball.drag*v*vx)/ball.mass)*dt) + FM.x*dt #updates x component of velocity vy = vy - 9.8*dt - (((ball.drag*v*vy)/ball.mass)*dt)# + FM.y*dt #updates y component of velocity '''This is where I believe my problem exists. I cannot figure out why the other two velocities are altered by the effect of the magnus force, but in this equation, y is not being altered at least noticeably.''' return x,y,z,vx,vy,vz
def vs_loop(): #pan_inc = 0.25 #zoom_inc = array((0.25,0.25,0.25)) pan_inc = 0.25 zoom_inc = array((0.05,0.05,0.05)) # for scene rotation with invariant light direction light_frame = vs.frame() for obj in vs.scene.lights: if isinstance(obj, vs.distant_light): obj.frame = light_frame # put distant lights in a frame prev_scene_forward = vs.vector(vs.scene.forward) # keep a copy of the old forward while True: if vs.scene.kb.keys: key = vs.scene.kb.getkey() if key == 'up': vs.scene.center = array(vs.scene.center) + array((0,pan_inc,0)) elif key == 'down': vs.scene.center = array(vs.scene.center) + array((0,-pan_inc,0)) elif key == 'left': vs.scene.center = array(vs.scene.center) + array((-pan_inc,0,0)) elif key == 'right': vs.scene.center = array(vs.scene.center) + array((pan_inc,0,0)) elif key == 'shift+up': vs.scene.range -= zoom_inc elif key == 'shift+down': vs.scene.range += zoom_inc if vs.scene.forward != prev_scene_forward: new = vs.scene.forward axis = vs.cross(prev_scene_forward, new) angle = new.diff_angle(prev_scene_forward) light_frame.rotate(axis=axis, angle=angle) prev_scene_forward = vs.vector(new)
def drawThumbPattern(pattern, i, gc, l, m, length): faces = pattern.faces center = vector(m * (i + 1) + l * (i + 1 / 2.0), l / 2 + m, 0) for face in faces: edge1 = face.vertices[1].coords - face.vertices[0].coords edge2 = face.vertices[-1].coords - face.vertices[0].coords if cross(edge1, edge2).z > 0: # the angle from edge1 to 2 is negative gc.SetBrush(wx.Brush('white')) else: gc.SetBrush(wx.Brush('yellow')) path = gc.CreatePath() for i in range(len(face.vertices)): vertex = face.vertices[i] coords = vector(vertex.coords.x, -vertex.coords.y) length = 100 # from center of the origami to a vertex vPosition = center + coords / length * l / 2 if i == 0: path.MoveToPoint(vPosition.x, vPosition.y) else: path.AddLineToPoint(vPosition.x, vPosition.y) path.CloseSubpath() gc.DrawPath(path)
def cross(self, other): temp = cross(self.v, other.v) return Vector((temp.x, temp.y, temp.z))
S_LENGTH_LABEL = vp.label(pos=S_LENGTH.pos, text="Fix Length", yoffset=-5, opacity=0, box=0, line=0) S_TEXT = vp.label(pos=(0, 12, 0), text="Yellow = Red x Green", opacity=0, box=0, line=0) FIXLENGTH = 0 FIXTHETA = 0 AVECTOR = vp.array([0, 0, -3.5]) BVECTOR = vp.vector(0, 3, 2) A = vp.arrow(pos=(0, 0, 0), shaftwidth=R, color=vp.color.red) B = vp.arrow(pos=(0, 0, 0), axis=BVECTOR, shaftwidth=R, color=vp.color.green) A.axis = AVECTOR CVECTOR = vp.cross(AVECTOR, BVECTOR) C = vp.arrow(pos=(0, 0, 0), axis=CVECTOR, shaftwidth=R, color=vp.color.yellow) vp.scene.autoscale = 0 vp.scene.forward = (-1, -.5, -1) DRAG = 0 while True: vp.rate(100) if vp.scene.mouse.events: M = vp.scene.mouse.getevent() if M.drag: DRAG = True OBS = None elif M.drop:
def bdipole(r): # calc magnetic fields at $\vec{r}$ b, rel = vp.vector(0, 0, 0), r - rs for i in range(len(ds)): # sum over segments b += vp.cross(ds[i], rel[i]) / vp.mag( rel[i])**3 # $\sum Id\vec{s}\times \vec{r}/r^3$ return b
def baseball(Y, t): # Y = [r, v] assumed v = Y[1] fm = alpha * vp.cross(omega, v) # Magnus force a = (fm - b2 * vp.mag(v) * v) / mass - [0, g, 0] # minus g-vec return np.array([v, a]) # np array
up=ex*np.cos(j)*rr+ey*np.sin(j)*rr+ez*(0)+center up=up.rotate(angle=r1data[k][0],axis=r1data[k][1]) up=up.rotate(angle=r2data[k][0],axis=r2data[k][1]) L.append((up.x,up.y,up.z)) down=ex*np.cos(j)*rru+ey*np.sin(j)*rru+ez*(h)+center down=down.rotate(angle=r1data[k][0],axis=r1data[k][1]) down=down.rotate(angle=r2data[k][0],axis=r2data[k][1]) L.append((down.x,down.y,down.z)) # if up.x>0: # continue hexagon.pos = L #ball=vs.sphere(pos=(0,0,0),radius=17.5) #fig = plt.figure() #ax = fig.add_subplot(111, projection='3d') ##ax.plot(xx,yy,zz,".") #ax.scatter(x,y,z,color="g",s=100) #ax.set_xlabel('x') #ax.set_ylabel('y') #ax.set_zlabel('z') #plt.show() #for i in range(len(x)): # print x[i],y[i],z[i] while 1: vs.rate(50) if vs.scene.forward != old: new = vs.scene.forward axis = vs.cross(old,new) angle = new.diff_angle(old) lframe.rotate(axis=axis, angle=angle) old = vs.vector(new)
def angular_momentum(self, pos = vector()): return cross(self.pos - pos, self.momentum)
scene = vp.display(title='Electric dipole', background=(.2,.5,1), forward=(0,-1,-.5), up=(0,0,1)) zaxis = vp.curve(pos=[(0,0,-r),(0,0,r)]) qpos = vp.sphere(pos=(0,0,.02), radius=0.01, color=(1,0,0)) qneg = vp.sphere(pos=(0,0,-.02), radius=0.01, color=(0,0,1)) c1 = vp.ring(pos=(0,0,0), radius=r, axis=(0,0,1), thickness=0.002) c2 = vp.ring(pos=(0,0,0), radius=r, axis=(0,1,0), thickness=0.002) theta, phi = np.linspace(0, np.pi, m), np.linspace(0, 2*np.pi, n) # grid phi, theta = vp.meshgrid(phi, theta) rs = r*np.sin(theta) x, y, z = rs*np.cos(phi), rs*np.sin(phi), r*np.cos(theta) # coord. for i in range(m): for j in range(n): rvec = vp.vector(x[i,j], y[i,j], z[i,j]) B = scale*vp.cross(rvec, vp.vector(0,0,1))/(r*r) # $\vec{r}\times \hat z/r^2$ E = vp.cross(B, rvec)/r # $\vec{B}\times \vec{r}/r$ vp.arrow(pos=rvec, axis=E, length=vp.mag(E), color=(1,1,0)) vp.arrow(pos=rvec, axis=B, length=vp.mag(B), color=(0,1,1))
def moment(point, end1, end2=vector(0, 0, 0)): '''Returns the moment defined as the distance between a point and a line formed by two endpoints, end1 and end2. All points must be given as 3d vectors''' return mag(cross(point - end2, point - end1)) / \ mag(end1 - end2)
rhatR = arrow(pos = P, axis = (P[0]-sourceR[0],P[1]-sourceR[1],P[2]-sourceR[2]),\ length=0.2, shaftwidth = 0.02, color = color.red) rhatL = arrow(pos= P, axis = (P[0]-sourceL[0],P[1]-sourceL[1],P[2]-sourceL[2]), \ length = 0.2 , shaftwidth = 0.02, color=color.blue) # Decide the direction of the current dl (CCW from the top)- at the location of the right infinitestimal # it is dlR dlR = vector(0, 0, -1) RVec = vector(P[0] - sourceR[0], P[1] - sourceR[1], P[2] - sourceR[2]) # Use Biot-Savart to calculate the infinitesimal contribution to the magnetic field # by one of the two infinitesimals dbR = arrow(pos=P, axis=cross(dlR, RVec), length=0.2, shaftwidth=0.02, color=(1, 0.7, 0)) # Same calculation for the symmetric infinitesimal dlL = vector(0, 0, 1) LVec = vector(P[0] - sourceL[0], P[1] - sourceL[1], P[2] - sourceL[2]) dbL = arrow(pos=P, axis=cross(dlL, LVec), length=0.2, shaftwidth=0.02, color=(0, 0.7, 1))
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()
def runge_lenz(self, o): # print(cross(self.momentum, cross(self.pos, self.momentum)) - pow(self.mass, 2.0) * o.mass * g * norm(self.pos - o.pos)) return cross(self.momentum, self.l()) - pow(self.mass, 2.0) * o.mass * g * norm(self.pos - o.pos)
def baseball(Y, t): # Y = [r, v] assumed v = Y[1] fm = alpha*vp.cross(omega, v) # Magnus force a = (fm - b2*vp.mag(v)*v)/mass - [0,g,0] # minus g-vec return np.array([v, a]) # np array
def bdipole(r): # calc magnetic fields at $\vec{r}$ b, rel = vp.vector(0,0,0), r-rs for i in range(len(ds)): # sum over segments b += vp.cross(ds[i], rel[i])/vp.mag(rel[i])**3 # $\sum Id\vec{s}\times \vec{r}/r^3$ return b