file: mandelbrot_mw.py |
1 | #################################################### |
2 | # Calculate Mandelbrot set and save it as a bmp image |
3 | # |
4 | # Parallel version uses master-worker approach, |
5 | # with master node at rank zero; the work units |
6 | # distributed to workers consist of a single |
7 | # image row. It needs at least two MPI nodes to work. |
8 | # |
9 | #################################################### |
10 | |
11 | import mpi |
12 | import bmp |
13 | |
14 | # maximal number of iterations to compute a pixel |
15 | MAX_ITER = 256 |
16 | |
17 | # pixel computation function |
18 | def pixel(c): |
19 | z = 0 |
20 | for i in range(MAX_ITER): |
21 | z = z*z+c |
22 | if abs(z) >= 2.0: |
23 | return i |
24 | return MAX_ITER |
25 | |
26 | # image dimensions |
27 | nx = 1024 |
28 | ny = 1024 |
29 | |
30 | workers = [] |
31 | for i in range(mpi.size): |
32 | workers.append(0) |
33 | |
34 | if mpi.rank == 0: |
35 | # "master" node: |
36 | |
37 | # number of jobs being processed and the next image row to compute |
38 | jobs = 0 |
39 | row = 0 |
40 | |
41 | # initialize list of image rows |
42 | image = [] |
43 | for i in range(ny): |
44 | image.append(-1) |
45 | |
46 | # assign initial work units to all workers |
47 | for n in range(1, mpi.size): |
48 | mpi.send(row, n) |
49 | row += 1 |
50 | jobs += 1 |
51 | |
52 | # master's main loop: |
53 | while jobs > 0: |
54 | # receive computed result from any worker |
55 | result, status = mpi.recv() |
56 | |
57 | workers[status.source] += 1 |
58 | |
59 | # incorporate newly computed row into image data |
60 | image[result[0]] = result[1] |
61 | |
62 | if row < ny: |
63 | # send new work unit to the (now) idle worker |
64 | mpi.send(row, status.source) |
65 | row += 1 |
66 | else: |
67 | # no jobs remain: dismiss the worker |
68 | mpi.send(-1, status.source) |
69 | jobs -= 1 |
70 | |
71 | # convert data to color image and save it in a file |
72 | bmp.write_image('image.bmp', nx, ny, image, MAX_ITER) |
73 | for w in range(1,mpi.size): |
74 | print workers[w],"tasks completed by worker",w |
75 | |
76 | else: |
77 | # "worker" node: |
78 | while 1: |
79 | # receive work unit info |
80 | row, status = mpi.recv() |
81 | # check if we're still needed |
82 | if row == -1: |
83 | break |
84 | # compute row of image |
85 | rdata = [] |
86 | |
87 | # Magic here... 4.0j is a complex number |
88 | c = 4.0j*row/ny-2.0j |
89 | for x in range(nx): |
90 | rdata += [pixel(c+4.0*x/nx-2.0)] |
91 | # send the result to master |
92 | mpi.send([row, rdata], 0) |
|