Newer
Older
# I found this example for PyCuda here:
# http://wiki.tiker.net/PyCuda/Examples/Mandelbrot
#
# An improved sequential/pure Python code was contributed
# by CRVSADER//KY <crusaderky@gmail.com>.
#
# I adapted it for PyOpenCL. Hopefully it is useful to someone.
# July 2010, HolgerRapp@gmx.net
#
# Mandelbrot calculate using GPU, Serial numpy and faster numpy
# Use to show the speed difference between CPU and GPU calculations
# ian@ianozsvald.com March 2010
# Based on vegaseat's TKinter/numpy example code from 2006
# http://www.daniweb.com/code/snippet216851.html#
# with minor changes to move to numpy from the obsolete Numeric
import time
from PIL import Image
# You can choose a calculation routine below (calc_fractal), uncomment
# one of the three lines to test the three variations
# Speed notes are listed in the same place
# set width and height of window, more pixels take longer to calculate
def calc_fractal_opencl(q, maxiter):
queue = cl.CommandQueue(ctx)
output = np.empty(q.shape, dtype=np.uint16)
mf = cl.mem_flags
q_opencl = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=q)
output_opencl = cl.Buffer(ctx, mf.WRITE_ONLY, output.nbytes)
prg = cl.Program(
ctx,
"""
#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : enable
__kernel void mandelbrot(__global float2 *q,
__global ushort *output, ushort const maxiter)
{
int gid = get_global_id(0);
float nreal, real = 0;
float imag = 0;
for(int curiter = 0; curiter < maxiter; curiter++) {
nreal = real*real - imag*imag + q[gid].x;
imag = 2* real*imag + q[gid].y;
if (real*real + imag*imag > 4.0f) {
prg.mandelbrot(
queue, output.shape, None, q_opencl, output_opencl, np.uint16(maxiter)
)
cl.enqueue_copy(queue, output, output_opencl).wait()
return output
def calc_fractal_serial(q, maxiter):
# calculate z using pure python on a numpy array
# note that, unlike the other two implementations,
# the number of iterations per point is NOT constant
z = np.zeros(q.shape, complex)
output = np.resize(
np.array(
0,
),
q.shape,
)
for iter in range(maxiter):
z[i] = z[i] * z[i] + q[i]
def calc_fractal_numpy(q, maxiter):
# calculate z using numpy, this is the original
# routine from vegaseat's URL
output = np.resize(
np.array(
0,
),
q.shape,
)
z = np.zeros(q.shape, np.complex64)
done = np.greater(abs(z), 2.0)
q = np.where(done, 0 + 0j, q)
z = np.where(done, 0 + 0j, z)
# choose your calculation routine here by uncommenting one of the options
calc_fractal = calc_fractal_opencl
# calc_fractal = calc_fractal_serial
# calc_fractal = calc_fractal_numpy
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
class Mandelbrot:
def draw(self, x1, x2, y1, y2, maxiter=30):
# draw the Mandelbrot set, from numpy example
xx = np.arange(x1, x2, (x2 - x1) / w)
yy = np.arange(y2, y1, (y1 - y2) / h) * 1j
q = np.ravel(xx + yy[:, np.newaxis]).astype(np.complex64)
start_main = time.time()
output = calc_fractal(q, maxiter)
end_main = time.time()
secs = end_main - start_main
print("Main took", secs)
self.mandel = (output.reshape((h, w)) / float(output.max()) * 255.0).astype(
np.uint8
)
def create_image(self):
""" "
create the image from the draw() string
"""
# you can experiment with these x and y ranges
self.draw(-2.13, 0.77, -1.3, 1.3)
self.im = Image.fromarray(self.mandel)
self.im.putpalette([i for rgb in ((j, 0, 0) for j in range(255))
for i in rgb])
def create_label(self):
# put the image on a label widget
self.image = ImageTk.PhotoImage(self.im)
self.label = tk.Label(self.root, image=self.image)
self.label.pack()
def run_tk(self):
self.root = tk.Tk()
self.root.title("Mandelbrot Set")
self.create_image()
self.create_label()
# start event loop
self.root.mainloop()
if __name__ == "__main__":
try:
import tkinter as tk
except ModuleNotFoundError:
test.create_image()
else:
from PIL import ImageTk
try:
test.run_tk()
except tk.TclError:
test.create_image()