code: def run_kernel(self, func, gpu_args, threads, grid):
          
          global_size = (grid[0]*threads[0], grid[1]*threads[1], grid[2]*threads[2])
          local_size = threads
          event = func(self.queue, global_size, local_size, *gpu_args)
          event.wait()
docs: runs the OpenCL kernel passed as 'func'
  
          :param func: An OpenCL Kernel
          :type func: pyopencl.Kernel
  
          :param gpu_args: A list of arguments to the kernel, order should match the
              order in the code. Allowed values are either variables in global memory
              or single values passed by value.
          :type gpu_args: list( pyopencl.Buffer, numpy.int32, ...)
  
          :param threads: A tuple listing the number of work items in each dimension of
              the work group.
          :type threads: tuple(int, int, int)
  
          :param grid: A tuple listing the number of work groups in each dimension
              of the NDRange.
          :type grid: tuple(int, int)