def evolve():
    global topMass, mainMass, oscForceAngle, oscAmp, omega, dt, t, mainMass_displacementTime_source, topMass_displacementTime_source, M, C, K, velOld, dispOld, lhs, F0, rhs, gamma, beta, accOld, x1, x2
    oscForceAngle+=omega*dt
    t+=dt
    
    F1_next=-oscAmp*cos(oscForceAngle)      #force applied to main mass
    F_next = np.array([[F1_next,0]])
    
    # Newmark method with gamma = 0.5 and beta = 0.25:
    # v_n+1 = v_n+dt*[(1-gamma)*a_n+gamma*a_n+1]
    # d_n+1 = d_n+dt*v_n+dt*dt*[(0.5-beta)*a_n+beta*a_n+1]
    # Ma_n+1 + Cv_n+1 + Kd_n+1 = F_n+1
    
    lhs = M+gamma*dt*C+beta*dt*dt*K
    rhs = F_next-C.dot(velOld+(1-gamma)*dt*accOld)-K.dot(dispOld+dt*velOld+dt*dt*(0.5-beta)*accOld)
    rhs_array = np.array([rhs[0][0],rhs[0][1]])
    
    accNew = inv(lhs).dot(rhs_array)
    velNew = velOld+(1-gamma)*dt*accOld+gamma*dt*accNew
    dispNew = dispOld+dt*velOld+dt*dt*(0.5-beta)*accOld+dt*dt*beta*accNew
    


    mainMass.move(Coord(0,dispNew[0]-dispOld[0])*baseSpring.kappa/3)  #move main mass by calculated displacement normalized with base spring stiffness    
    topMass.move(Coord(0,dispNew[1]-dispOld[1])*baseSpring.kappa/3)   #move top mass by calculated displacement normalized with base spring stiffness

    accOld = accNew         #a_n for next time step
    velOld = velNew         #v_n for next time step
    dispOld = dispNew       #d_n for next time step

    h1=mainMass.getTop()
    h2=topMass.getTop()
    
    mainMass_position = mainMass.currentPos['y'][0]
    topMass_position = topMass.currentPos['y'][0]
    mainMass_displacement = (mainMass_position - x1)*3
    topMass_displacement = (topMass_position - x2)*3
    mainMass_displacementTime_source.stream(dict(x=[t],y=[mainMass_displacement]))
    topMass_displacementTime_source.stream(dict(x=[t],y=[topMass_displacement]))
    forceTime_source.stream(dict(x=[t],y=[F1_next]))                                       
    
    # update force arrow
    F_for_vis = F1_next*5 #scale
    # draw arrow in correct direction
    if (F1_next<1e-10):
        arrow_line.stream(dict(x1=[3], x2=[3], y1=[h1-F_for_vis], y2=[h1]),rollover=1)
        arrow_offset.stream(dict(x1=[3], x2=[3], y1=[h1+0.1], y2=[h1]),rollover=1)
    else:
        arrow_line.stream(dict(x1=[3], x2=[3], y1=[h1-F_for_vis], y2=[h1]),rollover=1)
        arrow_offset.stream(dict(x1=[3], x2=[3], y1=[h1-0.1], y2=[h1]),rollover=1)

    # update position of m_1 and m_2 label    
    m1_label_source.data=dict(x=[0], y=[h1-2.5], t=['m'])
    m2_label_source.data=dict(x=[-3], y=[h2-2], t=['m'])
    m1_index_label_source.data=dict(x=[0.6], y=[h1-2.8], t=['1'])
    m2_index_label_source.data=dict(x=[-2.4], y=[h2-2.3], t=['2'])
示例#2
0
 def __init__(self, start, end, lam=1.0):
     # define dashpot constant
     self.lam = lam
     # save points
     self.start = Coord(start[0], start[1])
     self.end = Coord(end[0], end[1])
     self.origStart = self.start
     self.origEnd = self.end
     self.startNow = self.start
     self.endNow = self.end
     # find direction along which dashpot lies
     # (not normalised)
     self.direction = self.end - self.start
     # define (normalised) perpendicular vector for spike directions
     perpVect = self.direction.perp()
     # define initial positions of dashpot coordinates
     self.CasingStart = dict(
         x=[
             self.end.x - self.direction.x / 8.0 + perpVect.x / 2.0,
             self.start.x + self.direction.x / 8.0 + perpVect.x / 2.0,
             self.start.x + self.direction.x / 8.0 - perpVect.x / 2.0,
             self.end.x - self.direction.x / 8.0 - perpVect.x / 2.0
         ],
         y=[
             self.end.y - self.direction.y / 8.0 + perpVect.y / 2.0,
             self.start.y + self.direction.y / 8.0 + perpVect.y / 2.0,
             self.start.y + self.direction.y / 8.0 - perpVect.y / 2.0,
             self.end.y - self.direction.y / 8.0 - perpVect.y / 2.0
         ])
     self.Line1Start = dict(
         x=[self.start.x, self.start.x + self.direction.x / 8.0],
         y=[self.start.y, self.start.y + self.direction.y / 8.0])
     self.PistonStart = dict(
         x=[
             self.end.x - self.direction.x / 2.0 + perpVect.x / 2.0,
             self.end.x - self.direction.x / 2.0 - perpVect.x / 2.0
         ],
         y=[
             self.end.y - self.direction.y / 2.0 + perpVect.y / 2.0,
             self.end.y - self.direction.y / 2.0 - perpVect.y / 2.0
         ])
     self.Line2Start = dict(
         x=[self.end.x, self.end.x - self.direction.x / 2.0],
         y=[self.end.y, self.end.y - self.direction.y / 2.0])
     # Create ColumnDataSources with initial positions
     self.Casing = ColumnDataSource(data=self.CasingStart)
     self.Line1 = ColumnDataSource(data=self.Line1Start)
     self.Piston = ColumnDataSource(data=self.PistonStart)
     self.Line2 = ColumnDataSource(data=self.Line2Start)
     # once positions have been calculated direction is normalised
     self.direction = self.direction.direction()
     # objects that are influenced by the dashpot
     self.actsOn = []
 def __init__(self, mass):
     # initialise value
     self.mass = mass
     # create vector of external forces (besides gravity) acting on the mass
     self.nextStepForces = []
     self.nextStepObjForces = []
     # initialise velocity
     self.v = Coord(0, 0)
     # create vector of objects affected by this object
     self.affectedObjects = []
     self.currentPos = dict()
     self.shape = ColumnDataSource
示例#4
0
 def __init__(self, start, end, x0, kappa=1.0, spacing=1.0):
     start = Coord(start[0], start[1])
     end = Coord(end[0], end[1])
     # define spring constant
     self.kappa = kappa
     # define rest length (directional) and direction
     self.length = (end - start)
     self.direction = self.length / self.length.norm()
     self.length = self.direction * x0
     # define the number of coils with respect to the relaxed position of the spring
     self.nCoils = int(floor(x0 / spacing))
     # Create ColumnDataSource
     self.Position = ColumnDataSource(data=dict(x=[], y=[]))
     # objects that are influenced by the spring
     self.actsOn = []
     # draw spring
     self.draw(start, end)
def init_pos():
    topMass.moveTo(-5,x2,4,4)
    mainMass.moveTo(-6,x1,12,5)
    spring.compressTo(Coord(-4,x2),Coord(-4,x1+5))
    dashpot.compressTo(Coord(-2,x2),Coord(-2,x1+5),0)
    baseSpring.compressTo(Coord(-1,x1),Coord(-1,0))
    baseDashpot.compressTo(Coord(1,x1),Coord(1,0),0)
    topMass.resetLinks(spring,(-4,x2))
    topMass.resetLinks(dashpot,(-2,x2))
    mainMass.resetLinks(spring,(-4,x1+5))
    mainMass.resetLinks(dashpot,(-2,x1+5))
    mainMass.resetLinks(baseSpring,(-1,x1))
    mainMass.resetLinks(baseDashpot,(1,x1))
 def getVelAcc(self):
     # find the total force:
     # Start with gravitational force
     F = Coord(0, -self.mass * 9.81)
     for i in range(0, len(self.thisStepForces)):
         # add all forces acting on mass (e.g. spring, dashpot)
         F += self.thisStepForces.pop()
     # Find acceleration
     print(F)
     a = F / self.mass
     return [self.v.copy(), a, self.currentPos['y'][0]]
示例#7
0
    def draw(self, start, end):
        self.start = start.copy()
        self.end = end.copy()
        # find direction along which spring lies
        # (not normalised)
        direction = end - start
        # find normalising constant (=length)
        length = direction.norm()
        # define (normalised) perpendicular vector for spike directions
        perpVect = Coord(direction.y / length, -direction.x / length)
        # create values to help with loop
        Pos = dict(x=[], y=[])
        Zero = Coord(0, 0)
        wiggle = [Zero, perpVect, Zero, -perpVect]

        # add first points
        Pos['x'].append(start.x)
        Pos['y'].append(start.y)

        # loop over each coil
        for i in range(0, self.nCoils):
            # loop over the 4 points in the coil
            for j in range(0, 4):
                # save points
                step = direction * 0.05 + direction * 0.9 * float(
                    i + j / 4.0) / self.nCoils + wiggle[j]
                Pos['x'].append(start.x + step.x)
                Pos['y'].append(start.y + step.y)

        # add final points
        Pos['x'].append(end.x - 0.05 * direction.x)
        Pos['y'].append(end.y - 0.05 * direction.y)
        Pos['x'].append(end.x)
        Pos['y'].append(end.y)

        # add calculated points to figure
        self.Position.data = Pos
        # return length (with direction for overly compressed spring)
        return direction
 def resetLinks(self, obj, point):
     p = Coord(point[0], point[1])
     # initialise values for loop
     n = len(self.affectedObjects)
     i = 0
     while (i < n):
         # check for object
         if (self.affectedObjects[i][0] == obj):
             # if so update it to the new force
             self.affectedObjects[i][1] = p
             # and exit while loop
             i = n + 1
         i += 1
class Mass(object):
    ## create mass
    def __init__(self, mass):
        # initialise value
        self.mass = mass
        # create vector of external forces (besides gravity) acting on the mass
        self.nextStepForces = []
        self.nextStepObjForces = []
        # initialise velocity
        self.v = Coord(0, 0)
        # create vector of objects affected by this object
        self.affectedObjects = []
        self.currentPos = dict()
        self.shape = ColumnDataSource

    ## Add an object that is affected by the movement of the mass
    def linkObj(self, obj, point):
        p = Coord(point[0], point[1])
        # save the object and the point where it touches the object
        self.affectedObjects.append([obj, p])
        # tell the object that it is linked so it can also apply forces to the mass
        obj.linkTo(self, p)

    ## reset linking point between mass and object
    def resetLinks(self, obj, point):
        p = Coord(point[0], point[1])
        # initialise values for loop
        n = len(self.affectedObjects)
        i = 0
        while (i < n):
            # check for object
            if (self.affectedObjects[i][0] == obj):
                # if so update it to the new force
                self.affectedObjects[i][1] = p
                # and exit while loop
                i = n + 1
            i += 1

    ## Usually called by spring or dashpot to apply a force to the mass
    def applyForce(self, F, obj):
        # initialise values for loop
        n = len(self.nextStepForces)
        i = 0
        while (i < n):
            # check if object has already applied a force
            if (self.nextStepObjForces[i] == obj):
                # if so update it to the new force
                self.nextStepForces[i] = F
                # and exit while loop
                i = n + 1
            i += 1
        # if object was not found
        if (i == n):
            # add to lists
            self.nextStepForces.append(F)
            self.nextStepObjForces.append(obj)

    # function which saves the forces so movement of other masses does not
    # affect this mass's behaviour
    def FreezeForces(self):
        # save forces
        self.thisStepForces = list(self.nextStepForces)

    ## get Velocity and Acceleration at this timestep
    def getVelAcc(self):
        # find the total force:
        # Start with gravitational force
        F = Coord(0, -self.mass * 9.81)
        for i in range(0, len(self.thisStepForces)):
            # add all forces acting on mass (e.g. spring, dashpot)
            F += self.thisStepForces.pop()
        # Find acceleration
        print(F)
        a = F / self.mass
        return [self.v.copy(), a, self.currentPos['y'][0]]

    # displace mass by disp
    def move(self, disp):
        for i in range(0, len(self.currentPos['x'])):
            # move x and y co-ordinates
            self.currentPos['x'][i] += disp.x
            self.currentPos['y'][i] += disp.y
        # update ColumnDataSource
        self.shape.data = deepcopy(self.currentPos)
        # This affects all the affectedObjects
        for i in range(0, len(self.affectedObjects)):
            # tell object that it has been affected and must move the end at
            # point self.affectedObjects[i][1] by displacement
            self.affectedObjects[i][0].movePoint(self.affectedObjects[i][1],
                                                 disp)
            # N.B. calling this function refills nextStepForces for next timestep

            # change point so that it is accurate for next timestep
            self.affectedObjects[i][1] += disp

    def changeMass(self, mass):
        self.mass = mass

    def changeInitV(self, v):
        self.v = Coord(0, v)
 def linkObj(self, obj, point):
     p = Coord(point[0], point[1])
     # save the object and the point where it touches the object
     self.affectedObjects.append([obj, p])
     # tell the object that it is linked so it can also apply forces to the mass
     obj.linkTo(self, p)
 def changeInitV(self, v):
     self.v = Coord(0, v)