Skip to content
Snippets Groups Projects
demo_mandelbrot.py 4.93 KiB
Newer Older
  • Learn to ignore specific revisions
  • # 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>.
    #
    
    Holger Rapp's avatar
    Holger Rapp committed
    # I adapted it for PyOpenCL. Hopefully it is useful to someone.
    # July 2010, HolgerRapp@gmx.net
    #
    
    # Original readme below these lines.
    
    
    # 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
    
    
    import numpy as np
    
    # 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):
    
        ctx = cl.create_some_context()
    
        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)
    
    
        #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;
    
    
            output[gid] = 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) {
    
                     output[gid] = curiter;
    
        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 i in range(len(q)):
    
            for iter in range(maxiter):
    
                z[i] = z[i] * z[i] + q[i]
    
                if abs(z[i]) > 2.0:
    
                    output[i] = iter
                    break
    
    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)
    
    
        for it in range(maxiter):
    
            done = np.greater(abs(z), 2.0)
    
            q = np.where(done, 0 + 0j, q)
            z = np.where(done, 0 + 0j, z)
    
            output = np.where(done, it, output)
    
    # 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
    
    
    
    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__":
    
        test = Mandelbrot()
    
        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()