Ejemplo n.º 1
0
    def run(self):
        """ this is the simulation loop of each cell """
        cellsize = self.cellsize
        while self.iteration < NUM_ITER:
            # in each iteration, this cell's particles move randomly. some
            # particles might move out of the boundary of this cell, and need
            # to be sent to neighboring cells.
            # We could directly send the list of outgoing particles to each
            # neighbor cell, but this would cause Charm4py to pickle a possibly
            # long list of Particle objects, and is not the most efficient
            # option. Instead, for each neighbor, we insert the particle data
            # of outgoing particles into an array, and send that. This bypasses
            # pickling (Charm4py copies the contents of the array buffer
            # directly into a message)

            # we are sending an array of particle data to each neighbor
            outgoingParticles = {nb_idx: array.array('d') for nb_idx in self.neighbor_indexes}
            i = 0
            while i < len(self.particles):
                p = self.particles[i]
                p.perturb(cellsize)
                dest_cell = (int(p.coords[0] / cellsize[0]), int(p.coords[1] / cellsize[1]))
                if dest_cell != self.thisIndex:
                    # this particle is moving to a neighboring cell
                    outgoingParticles[dest_cell].extend(p.coords)
                    self.particles[i] = self.particles[-1]
                    self.particles.pop()
                else:
                    i += 1

            # send outgoing particles to neighboring cells
            for i, channel in enumerate(self.neighbors):
                channel.send(outgoingParticles[self.neighbor_indexes[i]])

            # receive incoming particles from neighboring cells. iawait iteratively
            # yields channels as they become ready (have data to receive)
            for channel in charm.iwait(self.neighbors):
                incoming = channel.recv()
                self.particles += [Particle(float(incoming[i]),
                                            float(incoming[i+1])) for i in range(0, len(incoming), 2)]

            if self.iteration % 10 == 0:
                # reduction to report the current max particles per cell.
                # this call is asynchronous and doesn't block me
                self.reduce(self.thisProxy[(0,0)].reportMax, len(self.particles), Reducer.max)

            if self.iteration % 20 == 0:
                # tell Charm that this cell is ready for load balancing.
                # load balancing will start when all the cells call this.
                self.AtSync()
                # now we need to exit the coroutine because the coroutine stack
                # doesn't migrate
                self.iteration += 1
                return

            # the cell proceeds to the next iteration without need for global synchronization
            self.iteration += 1

        # simulation done (when all the cells reach this point)
        self.reduce(self.sim_done_future)
Ejemplo n.º 2
0
    def work(self, mainProxy):
        """ this is the main simulation loop for each chare """

        # size of my rectangular portion of the image
        self.mywidth = IMAGE_WIDTH // CHARE_ARRAY_WIDTH
        self.myheight = IMAGE_HEIGHT // CHARE_ARRAY_HEIGHT
        self.setInitialConditions()

        i = self.thisIndex
        X, Y = CHARE_ARRAY_WIDTH, CHARE_ARRAY_HEIGHT
        # establish a Channel with neighbor chares in the 2D grid
        left = Channel(self, remote=self.thisProxy[(i[0]-1)%X, i[1]])
        right = Channel(self, remote=self.thisProxy[(i[0]+1)%X, i[1]])
        top = Channel(self, remote=self.thisProxy[i[0], (i[1]-1)%Y])
        bottom = Channel(self, remote=self.thisProxy[i[0], (i[1]+1)%Y])

        width, height = self.mywidth, self.myheight
        # coordinate where my portion of the image is located
        sx = self.thisIndex[0] * width
        sy = self.thisIndex[1] * height
        # data will store my portion of the image
        data = np.zeros(width*height*3, dtype=np.uint8)
        buffers = [None] * 4

        # run simulation now
        while True:
            top_edge = self.pressure[[0],:].reshape(width)
            bottom_edge = self.pressure[[-1],:].reshape(width)
            left_edge = self.pressure[:,[0]].reshape(height)
            right_edge = self.pressure[:,[-1]].reshape(height)

            # send ghost values to neighbors
            left.send(RIGHT, left_edge)
            right.send(LEFT, right_edge)
            bottom.send(UP, bottom_edge)
            top.send(DOWN, top_edge)

            # receive ghost values from neighbors. iawait iteratively yields
            # channels as they become ready (have data to receive)
            for channel in charm.iwait((left, right, bottom, top)):
                side, ghost_values = channel.recv()
                buffers[side] = ghost_values

            check_and_compute(height, width,
                              buffers[LEFT], buffers[RIGHT], buffers[UP], buffers[DOWN],
                              self.pressure, self.pressure_old, self.pressure_new)

            # advance to next step by shifting the data back one step in time
            self.pressure_old, self.pressure, self.pressure_new = self.pressure, self.pressure_new, self.pressure_old

            # draw my part of the image, plus a nice 1 pixel border along my
            # right/bottom boundary
            fill_subimage(data, width, height, self.pressure)
            # provide my portion of the image to the mainchare
            mainProxy.depositSubImage(data, (sx, sy), (width, height))
            # wait for message from mainchare to resume simulation
            self.resumeFuture = Future()
            reset = self.resumeFuture.get()
            if reset:
                self.setInitialConditions()
Ejemplo n.º 3
0
 def work(self, level, done_fut):
     msgs = 0
     start = LEVELS_START[level]
     me = self.thisProxy[self.thisIndex]
     channels = list(self.channels[level])
     for i in range(LEVELS_NUM_ITER[level]):
         random.shuffle(channels)
         for ch in channels:
             ch.send(me, start + i)
         for ch in charm.iwait(channels):
             remote, data = ch.recv()
             assert data == start + i
             assert ch.remote == remote
             assert remote in self.nbs[level]
             msgs += 1
     self.reduce(done_fut, msgs, Reducer.sum)
Ejemplo n.º 4
0
    def __init__(self, args):
        N = min(4, charm.numPes())
        g = Group(Test)
        channels = [Channel(self, g[i]) for i in range(N)]
        for i in range(N):
            g[i].work(self.thisProxy)

        channels.reverse()

        t0 = time.time()
        idx = 0
        for ch in charm.iwait(channels):
            assert ch.recv() == idx
            idx += 1
            print(time.time() - t0)
        assert idx == N
        exit()
Ejemplo n.º 5
0
def main(args):
    N = min(4, charm.numPes())
    g = Group(Test)
    futures = [Future() for _ in range(N)]
    for i in range(N):
        g[i].work(futures[i])

    futures.reverse()

    t0 = time.time()
    idx = 0
    for f in charm.iwait(futures):
        assert f.get() == idx
        idx += 1
        print(time.time() - t0)
    assert idx == N
    exit()
Ejemplo n.º 6
0
    def run(self):
        """ this is the main computation loop """
        iteration = 0
        converged = False
        while not converged and iteration < MAX_ITER:
            # send ghost faces to my neighbors. sends are asynchronous
            if not self.leftBound:
                self.left_nb.send(RIGHT, self.temperature[1, 1:blockDimY + 1])
            if not self.rightBound:
                self.right_nb.send(
                    LEFT, self.temperature[blockDimX, 1:blockDimY + 1])
            if not self.topBound:
                self.top_nb.send(BOTTOM, self.temperature[1:blockDimX + 1, 1])
            if not self.bottomBound:
                self.bottom_nb.send(
                    TOP, self.temperature[1:blockDimX + 1, blockDimY])

            # receive ghost data from neighbors. iawait iteratively yields
            # channels as they become ready (have data to receive)
            for nb in charm.iwait(self.nbs):
                direction, ghosts = nb.recv()
                if direction == LEFT:
                    self.temperature[0, 1:len(ghosts) + 1] = ghosts
                elif direction == RIGHT:
                    self.temperature[blockDimX + 1, 1:len(ghosts) + 1] = ghosts
                elif direction == TOP:
                    self.temperature[1:len(ghosts) + 1, 0] = ghosts
                elif direction == BOTTOM:
                    self.temperature[1:len(ghosts) + 1, blockDimY + 1] = ghosts
                else:
                    charm.abort('Invalid direction')

            max_error = check_and_compute(self.temperature,
                                          self.new_temperature, self.istart,
                                          self.ifinish, self.jstart,
                                          self.jfinish)
            self.temperature, self.new_temperature = self.new_temperature, self.temperature
            converged = self.allreduce(max_error <= THRESHOLD,
                                       Reducer.logical_and).get()
            iteration += 1

        if self.thisIndex == (0, 0):
            # notify main function that computation has ended and report the iteration number
            self.sim_done_future.send(iteration)