def __init__(self, reference, tangent): self.t = visual.norm(tangent) # make reference vector orthogonal to tangent proj_r_to_t = reference.dot(tangent) / tangent.dot(tangent) * tangent self.r = visual.norm(reference - proj_r_to_t) # make bitangent vector orthogonal to the others self.s = visual.norm(self.t.cross(self.r))
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 _set_plane_vectors(self): cx, cy, cz = self.center.getPosition() x, y, z = self.motors[0].getPosition() self.v1 = norm(vector(x-cx, y-cy, z-cz)) x, y, z = self.motors[2].getPosition() self.v2 = norm(vector(x-cx, y-cy, z-cz)) # Calculate pitch and roll self.pitch = 90 - degrees(self.v1.diff_angle(vector(0, 1, 0))) self.roll = degrees(self.v2.diff_angle(vector(0, 1, 0))) - 90 # calculate yaw, (this works if the quad is close to a horizontal position) if self.v1.z <= 0: self.yaw = degrees(self.v1.diff_angle(vector(1, 0, 0))) else: self.yaw = 360 - degrees(self.v1.diff_angle(vector(1, 0, 0)))
def c_acel(self, xm, obj): acel = v.vector(0, 0, 0) for i in obj: if i.id != self.id: acel += (i.mass * (v.norm(i.pos - xm) * G) / (v.mag(i.pos - xm)**2)) return acel
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 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 __setattr__(self, attr, val): old_val = 1.0 if attr == 'size': old_val = getattr(self, attr, 1.0) # Make sure the axis property of frames is normalized. """ if attr == 'axis' and len(val) == 3: norm = sqrt(val[0] ** 2 + val[1] ** 2 + val[2] ** 2) val = (val[0]/norm, val[1]/norm, val[2]/norm) super(MyFrame, self).__setattr__(attr, val) """ if attr in ['color', 'opacity', 'material']: super(MyFrame, self).__setattr__(attr, val) for obj in self.objects: setattr(obj, attr, val) elif attr == 'size': super(MyFrame, self).__setattr__('is_initialized', True) super(MyFrame, self).__setattr__(attr, val) # If an extrusion, no need to resize: we already resize before (only extrusions have an 'e' field) if getattr(self, 'e', False): pass else: for obj in self.objects: for p in size_loc_prop[obj.type]: setattr(obj, p, getattr(obj, p)*val/old_val) # Also adjust the distance of the frame from the origin to fit the scaling. Do this only the second time # this factor is changed (so that when reading from file we won't do this twice). """ if getattr(self, 'is_initialized', False): self.x *= val/old_val self.y *= val/old_val self.z *= val/old_val """ elif attr == 'up': # Make sure 'up' and 'axis' are perpendicular val = v.vector(val) val = v.norm(val - v.norm(self.axis) * val.dot(v.norm(self.axis))) super(MyFrame, self).__setattr__(attr, val) else: super(MyFrame, self).__setattr__(attr, val)
def sampleCurve(curve, sampleCount): points = [] tangents = [] parameterValues = [] step = 1.0 / (sampleCount - 1) t = 0 last_point = curve(t) points.append(last_point) parameterValues.append(0) for i in range(1, sampleCount): t += step current_point = curve(t) points.append(current_point) tangents.append(visual.norm(current_point - last_point)) parameterValues.append(t) last_point = current_point # use a point outside the [0; 1] interval to compute the tanget # note: the curve might not be always defined outside this interval! t += step tangents.append(visual.norm(curve(t) - last_point)) return (points, tangents, parameterValues)
def rotation_matrix(omega): theta = mag(omega) if theta == 0: return np.matrix(np.identity(3)) axis = norm(omega) a = cos(theta / 2) b, c, d = -axis * sin(theta / 2) aa, bb, cc, dd = a * a, b * b, c * c, d * d bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d return np.matrix([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)], [2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)], [2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])
def makespring(natom1, natom2, radius): """ make spring from nnth atom to iith atom""" if natom1 > natom2: r12 = ATOM[natom2].pos-ATOM[natom1].pos direct = vp.norm(r12) SPRINGS.append(vp.helix(pos=ATOM[natom1].pos+RS*direct, axis=(L-2*RS)*direct, radius=radius, color=SCOLOR, thickness=0.04)) #, shininess=0.9)) SPRINGS[-1].atom1 = ATOM[natom1] SPRINGS[-1].atom2 = ATOM[natom2] angle = SPRINGS[-1].axis.diff_angle(vp.vector(0, 1, 0)) # avoid pathologies if too near the y axis (default "up") if angle < 0.1 or angle > PI-0.1: SPRINGS[-1].up = vp.vector(-1, 0, 0)
def proj(a,b): '''Projects the vector a along the direction of b.''' return vector(dot(a, norm(b)) * norm(b))
T_step = step_interval s = sphere(make_trail=True, pos=[ride_radius + ride_radius2, 0, 0], radius=0.1) s.trail_object.color = color.yellow a_tangential = arrow(pos=[1, 0, 0], axis=[0, 1, 0], color=color.red) a_inward = arrow(pos=[1, 0, 0], axis=[-1, 0, 0], color=color.blue) for theta in arange(0, 100 * pi, T_step): rate(60) r = vector(ride_radius*cos(theta) + ride_radius2*cos(p*theta), \ ride_radius*sin(theta) + ride_radius2*sin(p*theta), 0) velocity = vector(-ride_radius*sin(theta)-ride_radius2*p*sin(p*theta), \ ride_radius*cos(theta)+ride_radius2*p*cos(p*theta),0) vel = str(velocity).strip('[]') acceleration = vector(-ride_radius*cos(theta) - ride_radius2*p**2*cos(p*theta), \ -ride_radius*sin(theta) - ride_radius2*p**2*sin(p*theta), 0) tangential_acceleration = (dot(velocity, acceleration) / mag(velocity)) * norm(velocity) tang_accel = str(tangential_acceleration).strip('[]') inward_acceleration = acceleration - tangential_acceleration in_accel = str(inward_acceleration).strip('[]') s.pos = r a_tangential.pos = r a_inward.pos = r a_tangential.axis = tangential_acceleration a_inward.axis = inward_acceleration data.append([theta, vel, tang_accel, in_accel]) for row in data: ws.append(row) ws.append(["Major Radius: ", r1]) ws.append(["Minor Radius: ", r2])
nl = 1 # nl = 100 CF = vp.frame(frame=ROTOR_FRAME, pos=(0, 0, THK / 2. + C1 / 2.0)) for i in range(nl): # Extrude rotor core profile to get the full core body GE3 = vp.extrusion(pos=[(0, 0, i * DLT), (0, 0, i * DLT + THK)], shape=G3, color=(0.7, 0.7, 0.705), twist=0.0, frame=CF) # Do the core wire windings # Here is a trick to build a saw-teeth profile, to represent many single windings N = 20 # coils VRIGHT = vp.vector(.3, 1.3) R = vp.mag(VRIGHT) / (2 * N) VRIGHT = vp.norm(VRIGHT) # S is the cross sectional profile of "winding block" S = vp.Polygon([(-.1, -.65), (0, -.65), (.3, .65), (-.1, .65)]) for n in range(N): RIGHT = vp.vector(0, -.65) + (R + n * 2 * R) * VRIGHT # Add saw-teeth on the block to represent wires S += vp.shapes.circle(pos=(RIGHT.x, RIGHT.y), radius=R, np=4) # Define the winding path as a rounded rectangle P = vp.shapes.rectangle(width=.5, height=THK) P += vp.shapes.circle(pos=(0, -THK / 2), radius=.25, np=10) P += vp.shapes.circle(pos=(0, +THK / 2), radius=.25, np=10) WRFS = [] for i in range(NS): # We need a separate frame for individiual winding section WRF = vp.frame(frame=CF, pos=(0, 2, THK / 2.))
if FIXLENGTH: FIXLENGTH = not FIXLENGTH S_LENGTH.color = (0.6, 0.6, 1.0) FIXTHETA = not FIXTHETA if FIXTHETA: S_THETA.color = (0.0, 1.0, 0.0) else: S_THETA.color = (0.6, 1.0, 0.6) if DRAG: vp.rate(100) NEWOBS = vp.scene.mouse.project(normal=vp.vector(1, 0, 0), d=0) if NEWOBS and (NEWOBS != OBS): OBS = NEWOBS if not FIXLENGTH and not FIXTHETA: BVECTOR = OBS if BVECTOR.mag > 20: BVECTOR = BVECTOR*(20/BVECTOR.mag) B.axis = BVECTOR elif FIXLENGTH: LENGTH = 3.9 BVECTOR = LENGTH*vp.norm(OBS) B.axis = BVECTOR elif FIXTHETA: LENGTH = vp.mag(OBS) BVECTOR = LENGTH*vp.norm(vp.vector(0, 0.3, 1)) B.axis = BVECTOR CVECTOR = vp.cross(AVECTOR, B.axis) C.axis = CVECTOR
F.pos = vp.transpose((vp.sin(T)-2, vp.cos(T)+2, 0*T)) # disk for T in vp.arange(0, 2*PI, 0.1): A.append(pos=(vp.cos(T), 0, vp.sin(T))) A.append(pos=(vp.cos(T), 0.2, vp.sin(T))) # box for i in range(8): P = vp.vector((i/4)%2 - 2.5, (i/2)%2 - 0.5, (i)%2 - 0.5) B.append(pos=P) # random sphere L = [] for i in range(1000): L.append(vp.vector(2, 0) + vp.norm(vp.vector( uniform(-1, 1), uniform(-1, 1), uniform(-1, 1)))) C.pos = L # lat/long sphere L = [] for T in vp.arange(0, 2*PI, 0.2): for s in vp.arange(0, PI, 0.1): L.append((vp.cos(T)*vp.sin(s)+2, vp.sin(T)*vp.sin(s)+2, vp.cos(s))) D.pos = L # modify the disk P = A P.color = (P.color[0]*2, P.color[1]*2, P.color[2]*2) while 1: vp.rate(10) if vp.scene.mouse.clicked:
from visual import vector, mag, norm from visual import sphere, rate, color, display from math import cos, sin, pi from numpy import arange d = display() m_earth = 100.0 m_sun = 10000000.0 g = 0.000001 r = vector(70.0, 0, 0) v = vector(0, 2.0, 0) s_earth = sphere(pos=[r.x, r.y, r.z], radius=1, color=color.white) s_sun = sphere(pos=[0, 0, 0], radius=2, color=color.yellow) d.autoscale = False while True: rate(30) a = -1 * norm(r) * ((g * m_earth * m_sun) / (mag(r)**2)) v = v + a r = r + v s_earth.pos = [r.x, r.y, r.z]
# disk for T in vp.arange(0, 2 * PI, 0.1): A.append(pos=(vp.cos(T), 0, vp.sin(T))) A.append(pos=(vp.cos(T), 0.2, vp.sin(T))) # box for i in range(8): P = vp.vector((i / 4) % 2 - 2.5, (i / 2) % 2 - 0.5, (i) % 2 - 0.5) B.append(pos=P) # random sphere L = [] for i in range(1000): L.append( vp.vector(2, 0) + vp.norm(vp.vector(uniform(-1, 1), uniform(-1, 1), uniform(-1, 1)))) C.pos = L # lat/long sphere L = [] for T in vp.arange(0, 2 * PI, 0.2): for s in vp.arange(0, PI, 0.1): L.append( (vp.cos(T) * vp.sin(s) + 2, vp.sin(T) * vp.sin(s) + 2, vp.cos(s))) D.pos = L # modify the disk P = A P.color = (P.color[0] * 2, P.color[1] * 2, P.color[2] * 2) while 1: vp.rate(10)
DLT = 0.05 THK = 5.04 nl = 1 # nl = 100 CF = vp.frame(frame=ROTOR_FRAME, pos=(0, 0, THK / 2.0 + C1 / 2.0)) for i in range(nl): # Extrude rotor core profile to get the full core body GE3 = vp.extrusion( pos=[(0, 0, i * DLT), (0, 0, i * DLT + THK)], shape=G3, color=(0.7, 0.7, 0.705), twist=0.0, frame=CF ) # Do the core wire windings # Here is a trick to build a saw-teeth profile, to represent many single windings N = 20 # coils VRIGHT = vp.vector(0.3, 1.3) R = vp.mag(VRIGHT) / (2 * N) VRIGHT = vp.norm(VRIGHT) # S is the cross sectional profile of "winding block" S = vp.Polygon([(-0.1, -0.65), (0, -0.65), (0.3, 0.65), (-0.1, 0.65)]) for n in range(N): RIGHT = vp.vector(0, -0.65) + (R + n * 2 * R) * VRIGHT # Add saw-teeth on the block to represent wires S += vp.shapes.circle(pos=(RIGHT.x, RIGHT.y), radius=R, np=4) # Define the winding path as a rounded rectangle P = vp.shapes.rectangle(width=0.5, height=THK) P += vp.shapes.circle(pos=(0, -THK / 2), radius=0.25, np=10) P += vp.shapes.circle(pos=(0, +THK / 2), radius=0.25, np=10) WRFS = [] for i in range(NS): # We need a separate frame for individiual winding section WRF = vp.frame(frame=CF, pos=(0, 2, THK / 2.0))
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 g_force(self, o): r = self.pos - o.pos if mag2(r) > 0: return -norm(self.pos - o.pos) * g * self.mass * o.mass / mag2(self.pos - o.pos) return vector()
def proj(a, b): '''Projects the vector a along the direction of b.''' return vector(dot(a, norm(b)) * norm(b))
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 arr(a, b): '''The unit vector starting at a.pos and ending at b.pos''' return norm(a.pos - b.pos)