Пример #1
0
 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))
Пример #2
0
 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
Пример #3
0
 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
Пример #4
0
 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
Пример #6
0
    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
Пример #7
0
    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
Пример #8
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
Пример #9
0
    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)
Пример #10
0
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]])
Пример #12
0
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)
Пример #13
0
def proj(a,b):
    '''Projects the vector a along the direction of b.'''
       
    return vector(dot(a, norm(b)) * norm(b))
Пример #14
0
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])
Пример #15
0
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.))
Пример #16
0
                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

Пример #17
0
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:
Пример #18
0
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]
Пример #19
0
# 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)
Пример #20
0
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))
Пример #21
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()
Пример #23
0
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)
Пример #25
0
def arr(a, b):
    '''The unit vector starting at a.pos and ending at b.pos'''
    return norm(a.pos - b.pos)