class Simulator():
    """Runs the brownian-motion simulation.

    :author: Peter Sander
    :author: ZHENG Yannan
    """
    def __init__(self, root: object, size=50, num_sapiens=50, num_infected=20):
        """Create a simulation with the given field size.

        :root: tkinter.Tk graphics object
        """
        self.size = size
        self._sapiens = []  # all sapiens in the simulation
        self._field = Field(size)
        Stats.step = 0
        self._view = SimulatorView(root, size)
        #self._colours = ('red', 'green', 'blue', 'yellow', 'magenta', 'cyan')
        self.colours = {
            State.SUSCEPTIBLE: 'slate blue',
            State.INFECTED: 'red',
            State.RECOVERED: 'spring green',
            State.DEAD: 'black'
        }
        Stats.I = num_infected
        Stats.S = num_sapiens - num_infected
        Stats.I0 = Stats.I
        self.reset(num_sapiens)

    def runLongSimulation(self) -> None:
        """Run the simulation from its current state for a reasonably
        long period, e.g. 500 steps.
        """
        self.simulate(500)

    def simulate(self, numSteps, delay=1) -> None:
        """Run the simulation from its current state for
        the given number of steps.

        :delay: Time (in secs) between each iteration.
        """

        Stats.step = 1
        while Stats.step <= numSteps:
            if Stats.isViable() == True:
                self.simulateOneStep()
                Stats.I0 = Stats.I

            time.sleep(delay)

    def simulateOneStep(self) -> None:
        """Run the simulation from its current state for a single step.
        """
        Stats.step += 1
        #  all _sapiens in motion
        for Sapiens in self._sapiens:
            if Stats.step == Sapiens.r_or_d:
                Sapiens.if_I_die()
            if Sapiens.colour != 'black':
                Sapiens.move()
        self._view.showStatus(Stats.step, self._sapiens)

    def reset(self, num_sapiens):
        """Reset the simulation to a starting location.
        """
        Stats.step = 0
        self._sapiens = []
        self.populate(num_sapiens)
        self._view.showStatus(Stats.step, self._sapiens)

    def populate(self, num_sapiens=50):
        """Populates the _field with randomly-locationed _sapiens.
        """
        self._field.clear()
        for p in range(Stats.S):
            location = Location(
                max=self.size)  # generate 0 <= random Location < size
            velocity = Velocity()
            #color = self._colours[random.randint(0, self._colours.__len__() - 1)]
            color = self.colours[State.SUSCEPTIBLE]
            Sapien_new = Sapiens(location, velocity, color, self._field)
            self._sapiens.append(Sapien_new)
            # generate random -1 <= random Velocity < 1
            # store sapiens with location and velocity
        for p in range(Stats.I):
            location = Location(max=self.size)
            velocity = Velocity()
            color = self.colours[State.INFECTED]
            Sapien_new = Sapiens(location, velocity, color, self._field)
            Sapien_new.r_or_d = Virus.RECOVERY_TIME
            self._sapiens.append(Sapien_new)
示例#2
0
class Simulator():
    """Runs the brownian-motion simulation.

    :author: Peter Sander
    """
    def __init__(self, root: object, size=50):
        """Create a simulation with the given field size.

        :root: tkinter.Tk graphics object
        """
        self.size = size
        self._sapiens = []  # all sapiens in the simulation
        self._field = Field(size)
        self.step = 0
        self._view = SimulatorView(root, size)
        self._colours = {
            State.SUSCEPTIBLE: 'slate blue',
            State.INFECTED: 'red',
            State.RECOVERED: 'spring green',
            State.DEAD: 'black'
        }
        self._stats = Stats()
        self.reset()

    def runLongSimulation(self) -> None:
        """Run the simulation from its current state for a reasonably
        long period, e.g. 500 steps.
        """
        self.simulate(500, 50)

    def simulate(self, numSapiens=50, delay=1.0) -> None:
        """Run the simulation from its current state for
        the given number of steps.

        :delay: Time (in secs) between each iteration.
        """
        self.step = 0
        self.populate(numSapiens)
        while self._stats.isViable(self._sapiens):
            self.simulateOneStep()
            print("R: " + str(self._stats.calculateR(self._sapiens)))
            # self.step += 1
            time.sleep(delay)

    def simulateOneStep(self) -> None:
        """Run the simulation from its current state for a single step.
        """
        collisions = Collisions()
        self.step += 1
        #  all _sapiens in motion
        for i in range(len(self._sapiens) - 1):
            for j in range(i + 1, len(self._sapiens)):
                if self._sapiens[i].location.row == self._sapiens[j].location.row \
                        and self._sapiens[i].location.col == self._sapiens[j].location.col:
                    collisions.collisions(self._sapiens[i], self._sapiens[j])
        for sapien in self._sapiens:
            sapien.setColour(self._colours[sapien.state])
            sapien.move()
            sapien.setColour(self._colours[sapien.state])
        self._view.showStatus(self.step, self._sapiens,
                              self._stats.state(self._sapiens))

    def reset(self):
        """Reset the simulation to a starting location.
        """
        self.step = 0
        self._sapiens = []
        self.populate(0)
        self._view.showStatus(self.step, self._sapiens,
                              self._stats.state(self._sapiens))

    def populate(self, numSapiens=50):
        """Populates the _field with randomly-locationed _sapiens.
        """
        self._field.clear()
        for s in range(numSapiens):
            location = Location(
                None, None, 0,
                self.size)  # generate 0 <= random location < size
            velocity = Velocity(randrange(-1, 1), randrange(
                -1, 1))  # generate random -1 <= random velocity < 1
            colour = self._colours[State.SUSCEPTIBLE]
            state = State.SUSCEPTIBLE
            self._sapiens.append(
                Sapiens(location, velocity, colour, self._field, state, 0,
                        0))  # append particle with location and velocity
        if len(self._sapiens) > 0:
            shuffle(self._sapiens)
            self._sapiens[0].state = State.INFECTED
class Simulator():
    """Runs the brownian-motion simulation.

    :author: Peter Sander
    :author: ZHENG Yannan
    """
    def __init__(self, root: object, size=50, num_particle=50):
        """Create a simulation with the given field size.

        :root: tkinter.Tk graphics object
        """
        self.size = size
        self._particles = []  # all particles in the simulation
        self._field = Field(size)
        self.step = 0
        self._view = SimulatorView(root, size)
        self._colours = {
            State.SUSCEPTIBLE: 'slate blue',
            State.INFECTED: 'red',
            State.RECOVERED: 'spring green',
            State.DEAD: 'black'
        }
        self.reset(num_particle)

    def Collision(self, num_particle):
        for p in range(num_particle - 1):
            for q in range(p, num_particle):
                if abs(self._particles[p].position.row -
                       self._particles[q].position.row) + abs(
                           self._particles[p].position.col -
                           self._particles[q].position.col) == 2:
                    if self._particles[p].colour == 'red' and self._particles[
                            q].colour == 'slate blue':
                        self._particles[q].colour = 'red'
                    if self._particles[q].colour == 'red' and self._particles[
                            p].colour == 'slate blue':
                        self._particles[p].colour = 'red'

    def runLongSimulation(self) -> None:
        """Run the simulation from its current state for a reasonably
        long period, e.g. 500 steps.
        """
        self.simulate(500)

    def simulate(self, numSteps, delay=1) -> None:
        """Run the simulation from its current state for
        the given number of steps.

        :delay: Time (in secs) between each iteration.
        """

        self.step = 1
        while self.step <= numSteps:
            self.simulateOneStep()
            # self.step += 1
            time.sleep(delay)

    def simulateOneStep(self) -> None:
        """Run the simulation from its current state for a single step.
        """
        self.step += 1
        #  all _particles in motion
        for particle in self._particles:
            if particle.colour != 'black':
                if particle.colour == 'red' or 'slate blue':
                    particle.move()
                    particle.cure()
                if particle.colour == 'spring green':
                    particle.move()
        self._view.showStatus(self.step, self._particles)
        self.Collision(50)

    def reset(self, num_particle):
        """Reset the simulation to a starting position.
        """
        self.step = 0
        self._particles = []
        self.populate(num_particle)
        self._view.showStatus(self.step, self._particles)

    def populate(self, num_particle=50):
        """Populates the _field with randomly-positioned _particles.
        """
        self._field.clear()
        particle_new = Particle(Position(max=self.size), Direction(),
                                self._colours.get(State.INFECTED), self._field)
        self._particles.append(particle_new)
        for p in range(num_particle - 1):
            position = Position(
                max=self.size)  # generate 0 <= random Position < size
            direction = Direction()
            color = self._colours.get(State.SUSCEPTIBLE)
            particle_new = Particle(position, direction, color, self._field)
            self._particles.append(particle_new)
示例#4
0
文件: Species.py 项目: snytav/Alma
class Species(object):
    def __init__(self, name, mass, charge, world):
        self.name = name
        self.mass = mass
        self.charge = charge
        self.world = world
        self.den = Field(world.ni, world.nj, world.nj, 1)

# returns the number of simulation particles

    def getNp(self):
        return particles.size()

# returns the number of real particles

    def getRealCount(self):
        return 1.0

# returns the species momentum

    def getMomentum(self):
        return 1.0

# returns the species kinetic energy

    def getKE(self):
        return 1.0

# moves all particles using electric field ef[]

    def advance(self):
        #get the time step
        dt = self.world.getDt()

        #save mesh bounds
        x0 = self.world.getX0()
        xm = self.world.getXm()

        #continue while particles remain
        for part in self.particles:
            #get logical coordinate of particle's position
            lc = self.world.XtoL(part.pos)

            #electric field at particle position
            ef_part = self.world.ef.gather(lc)

            #update velocity from F=qE
            part.vel += ef_part * (dt * self.charge / self.mass)

            #update position from v=dx/dt
            part.pos += part.vel * dt

            #did self particle leave the domain? reflect back
            for i in range(0, 3):
                if part.pos[i] < x0[i]:
                    part.pos[i] = 2 * x0[i] - part.pos[i]
                    part.vel[i] *= -1.0

                elif part.pos[i] >= xm[i]:
                    part.pos[i] = 2 * xm[i] - part.pos[i]
                    part.vel[i] *= -1.0

        if self.charge > 0:
            name = 'ions'
        else:
            name = 'electrons'

        writeParticles(self.particles, name, self.world.ts)
        return

# # compute number density
#  def computeNumberDensity(self):
#      den.clear()
#      for part in self.particles:
#          lc = world.XtoL(part.pos)
#          den.scatter(lc, part.mpw)
#
#      # divide by node volume
#      self.den.data =  np.divide(self.den.data,world.node_vol)

# adds a new particle

    def addParticle(self, pos, vel, mpw):
        # don't do anything (return) if pos outside domain bounds [x0,xd)
        if (not self.world.inBounds(pos)):
            return

        # get particle logical coordinate
        lc = self.world.XtoL(pos)

        # evaluate electric field at particle position
        ef_part = self.world.ef.gather(lc)

        # rewind velocity back by 0.5*dt*ef
        vel -= self.charge / self.mass * ef_part * (0.5 * self.world.getDt())

        return Particle(pos, vel, mpw)  # add to list

    # random load of particles in a x1-x2 box representing num_den number density
    def loadParticlesBox(self, x1, x2, num_den, num_mp):
        return

# quiet start load of particles in a x1-x2 box representing num_den number density

    def loadParticlesBoxQS(self, x1, x2, num_den, num_mp):
        box_vol = np.prod(np.subtract(x2, x1))  # box
        num_mp_tot = np.prod(np.subtract(
            num_mp, np.ones(3)))  # total number of simulation particles
        num_real = num_den * box_vol  # number of real particles double
        mpw = num_real / num_mp_tot  # macroparticle weight

        # compute particle grid spacing
        d = np.divide(np.subtract(x2, x1), np.subtract(num_mp, np.ones(3)))

        l = []
        # load particles on a equally spaced grid
        for i in range(0, num_mp[0]):
            for j in range(0, num_mp[1]):
                for k in range(0, num_mp[2]):
                    pos = np.add(x1, np.multiply(np.array([i, j, k]), d))

                    # shift particles on max faces back to the domain
                    if abs(pos[0] - x2[0]) < 1e-15: pos[0] -= 1e-4 * d[0]
                    if abs(pos[1] - x2[1]) < 1e-15: pos[1] -= 1e-4 * d[1]
                    if abs(pos[2] - x2[2]) < 1e-15: pos[2] -= 1e-4 * d[2]

                    w = 1
                    # relative weight
                    if i == 0 or i == (num_mp[0] - 1): w *= 0.5
                    if j == 0 or j == (num_mp[1] - 1): w *= 0.5
                    if k == 0 or k == (num_mp[2] - 1): w *= 0.5

                    # add rewind
                    vel = np.zeros(3)  # particle is stationary
                    p = self.addParticle(pos, vel, mpw *
                                         w)  # add a new particle to the array
                    l.append(p)

        self.particles = l

#TODO: check density evaluation at ts = 1
#      particles OK

    def computeNumberDensity(self):
        self.den.clear()
        if self.charge > 0:
            spname = 'ion'
        else:
            spname = 'el'

        name = spname + 'NumDens'
        volname = spname + 'VolDens'
        denname = spname + '_den'

        for part in self.particles:
            lc = self.world.XtoL(part.pos)
            self.den.scatter(lc, part.mpw)

        write_3D(self.world, self.den.data, denname, self.world.getTs(), 0)
        write_3D(self.world, self.world.node_vol, volname, self.world.getTs(),
                 0)

        # divide by node volume
        self.den.data = np.divide(self.den.data, self.world.node_vol)

        write_3D(self.world, self.den.data, name, self.world.getTs(), 0)
        return