diff options
author | Brett Weiland <brett_weiland@gmail.com> | 2024-06-11 14:50:14 -0500 |
---|---|---|
committer | Brett Weiland <brett_weiland@gmail.com> | 2024-06-11 14:50:14 -0500 |
commit | cb69732f68c0bd46c1574de16ce1aee6f38e439b (patch) | |
tree | def1daaec81a0d4cd7b3d44b2c26b9535e07579c |
64 files changed, 2435 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bde90c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +#*.png +*.mkv +*.mp4 @@ -0,0 +1 @@ +I will organize and collect this code all into one project some time! diff --git a/animation/asdf.png b/animation/asdf.png Binary files differnew file mode 100644 index 0000000..bbb1747 --- /dev/null +++ b/animation/asdf.png diff --git a/animation/gpu_migration.py b/animation/gpu_migration.py new file mode 100755 index 0000000..bbf718a --- /dev/null +++ b/animation/gpu_migration.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +x_min = (-periods * np.pi) + (square_x * np.pi) +x_max = (periods * np.pi) + (square_x * np.pi) +y_min = (-periods * np.pi) + (square_y * np.pi) +y_max = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 200 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +#ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +bruh = None + +def on_click(event): + global bruh + split_ratio = 1 + if (event.button is MouseButton.MIDDLE) and (event.inaxes): + # there's probably a way to set global coordinates; + # I don't expect this to go anywhere so I don't really care + on_x = ((event.xdata / img_res_x) * abs(x_max - x_min)) + x_min + on_y = ((event.ydata / img_res_y) * abs(y_max - y_min)) + y_min + + #I, uh, also don't know the best way to replicate the openCL code automaticly in python + #so ajust if nessesary + x_hops = [] + y_hops = [] + for i in range(iterations): + x_hops.append(((on_x - x_min) / abs(x_max - x_min)) * img_res_x) + y_hops.append(((on_y - y_min) / abs(y_max - y_min)) * img_res_y) + next_x = on_x/np.tan(on_y) + on_y = on_y/np.tan(on_x) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + print(y_hops[0]) + print(on_y) + print("{} hops".format(len(x_hops))) + if bruh: + bruh.pop(0).remove() + bruh = ax.plot(x_hops, y_hops) + plt.draw() + + + + print(on_x, on_y) + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + + +mp_image = None + +print("Rendering {} frames...".format(frames)) +plt.show(block=False) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated="True", interpolation='none') + if frame_i == 0: + mp_image = rendered_frame + else: + pass + #mp_image.set_array(image) + rendered_frames.append([rendered_frame]) + bar_total() + #fig.canvas.draw() + #fig.canvas.flush_events() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + ax.imshow(image, norm="log", aspect="auto", cmap=cmap) + fig.savefig(single_frame_save) + plt.autoscale(False) + plt.connect('motion_notify_event', on_click) + plt.show() + + diff --git a/animation/kernel.c b/animation/kernel.c new file mode 100644 index 0000000..9c99b2b --- /dev/null +++ b/animation/kernel.c @@ -0,0 +1,30 @@ +__kernel void basic_test() { + printf("this cores ID: (%lu, %lu)\n", get_global_id(0), get_global_id(1)); +} +double cosecant_single(double a, double b) { return a / tan(b); } +double secant_single(double a, double b) { return a / sin(b); } + +__kernel void render_frame(__global unsigned int *frame_output, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double r) { + unsigned int iter; + + double x_cart = (get_global_id(0) * x_step) + x_start; + double y_cart = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + + double x = sqrt(pow(x_cart, 2) + pow(y_cart, 2)); + double y = atan(y_cart / x_cart); + double next_x; + + for(iter = 0; iter < iterations; iter++) { + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + frame_output[img_index] = iter; +} diff --git a/animation/notes b/animation/notes new file mode 100644 index 0000000..50249d7 --- /dev/null +++ b/animation/notes @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar + +img_res_x = 2000 +img_res_y = 2000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "./animations" +frames = 120 + +rendered_frames = [] + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +opencl_context = cl.create_some_context() +opencl_queue = cl.CommandQueue(opencl_context) + + +#def render(): +# image = np.empty([img_res_y, img_res_x]) +# print("Rendering frames") +# with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: +# for frame in range(frames): +# split_ratio = frame / frames +# for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): +# for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): +# on_x = x +# on_y = y +# for i in range(iterations): +# next_x = (split_ratio * (on_x/np.sin(on_y))) + ((1 - split_ratio) * on_x/np.tan(on_y)) +# on_y = (split_ratio * (on_y/np.sin(on_x))) + ((1 - split_ratio) * on_y/np.tan(on_x)) +# on_x = next_x +# if on_x**2 + on_y**2 > escape: +# break +# image[pix_y][pix_x] = i +# rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated=False) +# rendered_frames.append([rendered_frame]) +# bar_total() + +def display(): + print(rendered_frames) + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save("test.mp4") + plt.show() + +render() +display() @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +from alive_progress import alive_bar + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = .25 +square_x = 1 +square_y = 1 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + + +image = np.empty([img_res_y, img_res_x]) + +with alive_bar(img_res_y, bar = 'filling', spinner = 'waves') as bar: + for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + completed_ratio = (((pix_x * pix_y * 1)) / total_pixels) + next_x = (completed_ratio * (on_x/np.sin(on_y))) + ((1 - completed_ratio) * on_x/np.tan(on_y)) + on_y = (completed_ratio * (on_y/np.sin(on_x))) + ((1 - completed_ratio) * on_y/np.tan(on_x)) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + image[pix_y][pix_x] = i + bar() + + + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +fig.savefig("linear_transform_sin_tan_arnolds_tongue_hotspot.png") +plt.show() diff --git a/collective/.gpu_migration.py.swo b/collective/.gpu_migration.py.swo Binary files differnew file mode 100644 index 0000000..4806821 --- /dev/null +++ b/collective/.gpu_migration.py.swo diff --git a/collective/.gpu_migration.py.swp b/collective/.gpu_migration.py.swp Binary files differnew file mode 100644 index 0000000..bc46962 --- /dev/null +++ b/collective/.gpu_migration.py.swp diff --git a/collective/.kernel.c.swp b/collective/.kernel.c.swp Binary files differnew file mode 100644 index 0000000..7e1f62d --- /dev/null +++ b/collective/.kernel.c.swp diff --git a/collective/gpu_migration.py b/collective/gpu_migration.py new file mode 100755 index 0000000..9536561 --- /dev/null +++ b/collective/gpu_migration.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import matplotlib.style as mplstyle +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton +from PIL import Image + +# HELLO READER ------------------------------------------------------------------------ +# yes, I know this script is horrid, but it's more of a scratchpad to quickly test ideas +# and not anything I'm ever going to show anyone else. + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = -2 + +escape = 10000 +iterations = (255*3) +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.double) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) + +manual_limits = [15.832664460420503, + 16.161782579162786, + 0.21263776938088172, + 0.2668613889327035] + + +#ax.invert_yaxis() +ax.set_xlim((-periods * np.pi) + (square_x * np.pi), (periods * np.pi) + (square_x * np.pi)) +ax.set_ylim((-periods * np.pi) + (square_y * np.pi), (periods * np.pi) + (square_y * np.pi)) +#ax.set_xlim(manual_limits[0], manual_limits[1]) +#ax.set_ylim(manual_limits[2], manual_limits[3]) + +#ax.set_axis_off() +fig.add_axes(ax) +mplstyle.use('fast') + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + + + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + +temp_render_hook = False +mp_image = None + +def render(axes): + global temp_render_hook + global mp_image + if not temp_render_hook: + temp_render_hook = True + x_min = axes.get_xlim()[0] + x_max = axes.get_xlim()[1] + y_min = axes.get_ylim()[1] + y_max = axes.get_ylim()[0] + print(axes.get_ylim()) + compiled_kernel.render_frame_curvature(opencl_queue, image.shape, None, image_buffer, mask_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + print("kernel") + if mp_image == None: + mp_image = ax.imshow(image, norm="linear", aspect="auto", cmap=cmap, interpolation='none', extent=(x_min, x_max, y_min, y_max)) # TODO + else: + mp_image.set(extent=(x_min, x_max, y_min, y_max)) + #ax.set_aspect('equal') + #mp_image.set_data(image) + mp_image.set_array(image) + + + fig.canvas.draw_idle() + fig.canvas.flush_events() + temp_render_hook = False + +#plt.ion() + +#open image +mask_path = "mask.png" +mask = np.asarray(Image.open(mask_path).convert("L").resize((img_res_x, img_res_y)), dtype=np.double) +#mask = np.zeros((img_res_x, img_res_y), dtype=np.double) +mask.setflags(write=1) +mask /= np.max(mask) # normalize +#print(mask.shape) +#print(mask.dtype) +#print(mask) +#ax.imshow(mask, norm="linear") +#plt.show() + +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) +mask_buffer = cl.Buffer(opencl_context, cl.mem_flags.READ_ONLY, mask.nbytes) +cl.enqueue_copy(opencl_queue, mask_buffer, mask).wait() +#mask_buffer = cl.array.Array(opencl_context,mask.shape, dtype=np.uint8, data=mask) + +#move to render +print("Rendering {} frames...".format(frames)) +if frames > 1: + x_min = ax.get_xlim()[0] + x_max = ax.get_xlim()[1] + y_min = ax.get_ylim()[1] + y_max = ax.get_ylim()[0] + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame_curvature(opencl_queue, image.shape, None, image_buffer, mask_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i/frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="linear", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + ax.callbacks.connect('ylim_changed', render) + ax.callbacks.connect('xlim_changed', render) + render(ax) + plt.savefig("out_texture.png") + plt.show(block=True) diff --git a/collective/kernel.c b/collective/kernel.c new file mode 100644 index 0000000..f3982a6 --- /dev/null +++ b/collective/kernel.c @@ -0,0 +1,116 @@ +//#include <math.h> +#define PI 3.141592653589793115997963468544185161590576171875 + +double cosecant_single(double a, double b) { return a / cos(b); } +double secant_single(double a, double b) { return a / cos(b); } + +/** +__kernel void render_frame_orbit_trap(__global double *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + + const vec2 point = (0, 0); + + unsigned int result; + unsigned int iter; + + double min_distance = DBL_MAX; + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = mask[img_index]; + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + frame_output[img_index] = total_curve / iter; + +} +**/ + + +__kernel void render_frame_curvature(__global double *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + unsigned int iter; + + double x_cart = (get_global_id(0) * x_step) + x_start; + double y_cart = (get_global_id(1) * y_step) + y_start; + double x = sqrt(pow(x_cart, 2) + pow(y_cart, 2)); + double y = atan(y_cart / x_cart); + + //double x = (get_global_id(0) * x_step) + x_start; + //double y = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + double total_curve = 0; + + //just found out vectors are a thing + double2 lp[3]; + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = mask[img_index]; + next_x = (r * secant_single(x, y)) + ((1 - r) * cosecant_single(x, y)); + y = (r * secant_single(y, x)) + ((1 - r) * cosecant_single(y, x)); + x = next_x; + + if((pow(x, 2) + pow(y, 2)) >= escape) break; + lp[2] = lp[1]; + lp[1] = lp[0]; + lp[0] = (double2)(x, y); //why do I have to cast this? hope no accuracy lost + + /** + if(img_index == 254234) { + printf("%u\n", ratio); + } + **/ + if(iter >= 2) { + double curl = acos(dot((lp[0] - lp[1]), (lp[2] - lp[1])) / (distance(lp[0], lp[1]) * distance(lp[2], lp[1]))); + total_curve = (total_curve + curl); + } + } + frame_output[img_index] = total_curve / iter; +} + + +__kernel void render_frame(__global double *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double x_cart = (get_global_id(0) * x_step) + x_start; + double y_cart = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + double x = sqrt(pow(x_cart, 2) + pow(y_cart, 2)); + double y = atan(y_cart / x_cart); + + //double x = (get_global_id(0) * x_step) + x_start; + //double y = (get_global_id(1) * y_step) + y_start; + + + unsigned int iter; + + //vec2 pos; + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = ratio; + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + //if(distance(pos) >= escape) break; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + + //TODO turn back to int whenever + frame_output[img_index] = (double)iter; + //frame_output[img_index] = mask[img_index] * 255; +} diff --git a/collective/mask.png b/collective/mask.png new file mode 120000 index 0000000..afb5f75 --- /dev/null +++ b/collective/mask.png @@ -0,0 +1 @@ +../masks/clouds.png
\ No newline at end of file diff --git a/collective/notes b/collective/notes new file mode 100644 index 0000000..50249d7 --- /dev/null +++ b/collective/notes @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar + +img_res_x = 2000 +img_res_y = 2000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "./animations" +frames = 120 + +rendered_frames = [] + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +opencl_context = cl.create_some_context() +opencl_queue = cl.CommandQueue(opencl_context) + + +#def render(): +# image = np.empty([img_res_y, img_res_x]) +# print("Rendering frames") +# with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: +# for frame in range(frames): +# split_ratio = frame / frames +# for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): +# for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): +# on_x = x +# on_y = y +# for i in range(iterations): +# next_x = (split_ratio * (on_x/np.sin(on_y))) + ((1 - split_ratio) * on_x/np.tan(on_y)) +# on_y = (split_ratio * (on_y/np.sin(on_x))) + ((1 - split_ratio) * on_y/np.tan(on_x)) +# on_x = next_x +# if on_x**2 + on_y**2 > escape: +# break +# image[pix_y][pix_x] = i +# rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated=False) +# rendered_frames.append([rendered_frame]) +# bar_total() + +def display(): + print(rendered_frames) + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save("test.mp4") + plt.show() + +render() +display() diff --git a/collective/out.png b/collective/out.png Binary files differnew file mode 100644 index 0000000..5011695 --- /dev/null +++ b/collective/out.png diff --git a/collective/out_grad.png b/collective/out_grad.png Binary files differnew file mode 100644 index 0000000..26fb1f1 --- /dev/null +++ b/collective/out_grad.png diff --git a/collective/out_texture.png b/collective/out_texture.png Binary files differnew file mode 100644 index 0000000..8031ab1 --- /dev/null +++ b/collective/out_texture.png diff --git a/collective/texput.log b/collective/texput.log new file mode 100644 index 0000000..d13b81a --- /dev/null +++ b/collective/texput.log @@ -0,0 +1,21 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024/Arch Linux) (preloaded format=pdflatex 2024.4.22) 28 APR 2024 21:33 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +** + +! Emergency stop. +<*> + +End of file on the terminal! + + +Here is how much of TeX's memory you used: + 3 strings out of 476076 + 113 string characters out of 5793775 + 1925187 words of memory out of 5000000 + 22212 multiletter control sequences out of 15000+600000 + 558069 words of font info for 36 fonts, out of 8000000 for 9000 + 14 hyphenation exceptions out of 8191 + 0i,0n,0p,13b,6s stack positions out of 10000i,1000n,20000p,200000b,200000s +! ==> Fatal error occurred, no output PDF file produced! diff --git a/cool_places b/cool_places new file mode 100644 index 0000000..6a9367d --- /dev/null +++ b/cool_places @@ -0,0 +1,6 @@ +windows into space + 15.832664460420503 + 16.161782579162786 + + 0.21263776938088172 + 0.2668613889327035 diff --git a/field_tests/backup b/field_tests/backup new file mode 100644 index 0000000..2e60664 --- /dev/null +++ b/field_tests/backup @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +from alive_progress import alive_bar + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = .25 +square_x = 1 +square_y = 1 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + + +image = np.empty([img_res_y, img_res_x]) + +with alive_bar(img_res_y, bar = 'filling', spinner = 'waves') as bar: + for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + completed_ratio = (((pix_x * pix_y * 1)) / total_pixels) + next_x = (completed_ratio * (on_x/np.sin(on_y))) + ((1 - completed_ratio) * on_x/np.tan(on_y)) + on_y = (completed_ratio * (on_y/np.sin(on_x))) + ((1 - completed_ratio) * on_y/np.tan(on_x)) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + image[pix_y][pix_x] = i + bar() + + + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +fig.savefig("linear_transform_sin_tan_arnolds_tongue_hotspot.png") +plt.show() diff --git a/field_tests/basic_field_test.py b/field_tests/basic_field_test.py new file mode 100644 index 0000000..faf3c2c --- /dev/null +++ b/field_tests/basic_field_test.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +from alive_progress import alive_bar + +img_res_x = 100 +img_res_y = 100 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +#xmin = (-periods * np.pi) + (square_x * np.pi) +#xmax = (periods * np.pi) + (square_x * np.pi) +#ymin = (-periods * np.pi) + (square_y * np.pi) +#ymax = (periods * np.pi) + (square_y * np.pi) + +xmin = -10 +xmax = 10 +ymin = -10 +ymax = 10 + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + + +image = np.empty([img_res_y, img_res_x]) +grid = np.meshgrid(np.linspace(ymin, ymax, img_res_y), np.linspace(xmin, xmax, img_res_x)) +print(grid[0].dtype) + + +class point_charge(): + def __init__(self, x, y, c, mod): + self.x = x + self.y = y + self.c = c + self.mod = mod + def get_field(self, to_x, to_y): + if(self.mod): + to_x = (to_x % self.mod) + to_y = (to_y % self.mod) + return ( + ((self.c * (self.x - to_x)) / ((self.x - to_x)**2 + (self.y - to_y)**2)**1.5), + ((self.c * (self.y - to_y)) / ((self.x - to_x)**2 + (self.y - to_y)**2)**1.5)) + +#will remove all the point charge code if it turns out to be good enough to be impliemnted into openCL +#point_charges = [point_charge(-5, -5, 100), point_charge(-5, 5, -100), point_charge(5, 0, 100)] +point_charges = [point_charge(5,5, 100, 10), point_charge(0,0,-100, 0)] + + +plt.ion() +ax = plt.gca() +fig = plt.gcf() +ax.set_autoscale_on(False) +ax.set_xlim([xmin, xmax]) +ax.set_ylim([ymin, ymax]) + +vector_arrows = None + +def show_field(): + global vector_arrows + grid_f = np.zeros_like(grid) + for p in point_charges: + grid_f += p.get_field(grid[0], grid[1]) + #plt.streamplot(grid[0], grid[1], grid_f[0], grid_f[1], density=5) + vector_arrows = plt.quiver(grid[0], grid[1], grid_f[0], grid_f[1]) + plt.show(block=False) + plt.pause(.1) + + +show_field() + +timestep = .1 +def test_sim(): + particle_grid = np.meshgrid(np.linspace(ymin, ymax, 100), np.linspace(xmin, xmax, 100)) + pos = particle_grid + acceleration = np.zeros_like(particle_grid) + velocity = np.zeros_like(particle_grid) + velocity = [np.ones_like(particle_grid[0]) * 1, np.ones_like(particle_grid[0]) * .5] + mass = 10 + charge = 1 + particle_plot = ax.plot(velocity[0], velocity[1], 'bo', animated=True) + #velocity += .1 + + background = fig.canvas.copy_from_bbox(ax.bbox) + ax.draw_artist(vector_arrows) + fig.canvas.blit(fig.bbox) + + while True: + fig.canvas.restore_region(background) + field = np.zeros_like(particle_grid) + # TODO can make this quicker by skipping initilization + for p in point_charges: + field += p.get_field(pos[0], pos[1]) + acceleration = ((charge * field) / mass) * timestep + #print(acceleration) + velocity += acceleration * timestep + pos += velocity * timestep + + fig.canvas.restore_region(background) + particle_plot[0].set_data(pos[0],pos[1]) + ax.draw_artist(particle_plot[0]) + fig.canvas.blit(fig.bbox) + fig.canvas.flush_events() + plt.pause(1/60) + + #fig.canvas.draw_idle() +test_sim() + +exit(1) + + + + + +#with alive_bar(iterations, bar = 'filling', spinner = 'waves') as bar: +# for i in range(iterations): +# next_x = xx / np.sin(yy) +# yy = yy / np.sin(xx) +# xx = next_x +# bar() +#image = np.vstack([xx.ravel(), yy.ravel()]) + + +#meshgrid makes things slower as we can't test individual points for breaking to infinity +fractal_test = False +if fractal_test: + with alive_bar(img_res_y, bar = 'filling', spinner = 'waves') as bar: + for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + completed_ratio = (((pix_x * pix_y * 1)) / total_pixels) + next_x = (completed_ratio * (on_x/np.sin(on_y))) + ((1 - completed_ratio) * on_x/np.tan(on_y)) + on_y = (completed_ratio * (on_y/np.sin(on_x))) + ((1 - completed_ratio) * on_y/np.tan(on_x)) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + image[pix_y][pix_x] = i + bar() +else: + exit() + + +exit(1) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +fig.savefig("linear_transform_sin_tan_arnolds_tongue_hotspot.png") +plt.show() diff --git a/field_tests/field.py b/field_tests/field.py new file mode 100755 index 0000000..af2abbf --- /dev/null +++ b/field_tests/field.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +from alive_progress import alive_bar + +img_res_x = 250 +img_res_y = 250 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +#xmin = -10 +#xmax = 10 +#ymin = -10 +#ymax = 10 + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + + +grid = np.meshgrid(np.linspace(ymin, ymax, 200), np.linspace(xmin, xmax, 200)) +#image = np.meshgrid(np.linspace(ymin, ymax, img_res_y), np.linspace(xmin, xmax, img_res_x)) +image = np.zeros([img_res_y, img_res_x], dtype=np.double) + + +class point_charge(): + def __init__(self, x, y, c, mod): + self.x = x + self.y = y + self.c = c + self.mod = mod + def get_field(self, to_x, to_y): + if(self.mod): + to_x = (to_x % self.mod) + to_y = (to_y % self.mod) + return np.array([ + ((self.c * (self.x - to_x)) / ((self.x - to_x)**2 + (self.y - to_y)**2)**1.5), + ((self.c * (self.y - to_y)) / ((self.x - to_x)**2 + (self.y - to_y)**2)**1.5)]) + +#will remove all the point charge code if it turns out to be good enough to be impliemnted into openCL +#point_charges = [point_charge(-5, -5, 100), point_charge(-5, 5, -100), point_charge(5, 0, 100)] +#point_charges = [point_charge(-1,-1, 100, 10), point_charge(1,1,-100, 0)] +point_charges = [] + + +#plt.ion() +ax = plt.gca() +fig = plt.gcf() +#ax.set_autoscale_on(False) +#ax.set_xlim([xmin, xmax]) +#ax.set_ylim([ymin, ymax]) + +vector_arrows = None + +def show_field(): + global vector_arrows + grid_f = np.zeros_like(grid) + for p in point_charges: + grid_f += p.get_field(grid[0], grid[1]) + #plt.streamplot(grid[0], grid[1], grid_f[0], grid_f[1], density=5) + vector_arrows = plt.quiver(grid[0], grid[1], grid_f[0], grid_f[1]) + plt.show(block=False) + plt.pause(.1) + + +#show_field() + +timestep = .1 +def test_sim(): + particle_grid = np.meshgrid(np.linspace(ymin, ymax, 100), np.linspace(xmin, xmax, 100)) + pos = particle_grid + acceleration = np.zeros_like(particle_grid) + velocity = np.zeros_like(particle_grid) + velocity = [np.ones_like(particle_grid[0]) * 1, np.ones_like(particle_grid[0]) * .5] + mass = 10 + charge = 1 + particle_plot = ax.plot(velocity[0], velocity[1], 'bo', animated=True) + #velocity += .1 + + background = fig.canvas.copy_from_bbox(ax.bbox) + ax.draw_artist(vector_arrows) + fig.canvas.blit(fig.bbox) + + while True: + fig.canvas.restore_region(background) + field = np.zeros_like(particle_grid) + # TODO can make this quicker by skipping initilization + for p in point_charges: + field += p.get_field(pos[0], pos[1]) + acceleration = ((charge * field) / mass) * timestep + #print(acceleration) + velocity += acceleration * timestep + pos += velocity * timestep + + fig.canvas.restore_region(background) + particle_plot[0].set_data(pos[0],pos[1]) + ax.draw_artist(particle_plot[0]) + fig.canvas.blit(fig.bbox) + fig.canvas.flush_events() + plt.pause(1/60) + + #fig.canvas.draw_idle() +#test_sim() + +#exit(1) + + +max_timesteps = 10 + +def get_fractal_iter(img): + next_x = img[1][y][x] / np.sin(img[0][y][x]) + img[0][y][x] = img[0][y][x] / np.sin(img[1][y][x]) + img[1][y][x] = next_x + if (np.square(img[0][y][x]) + np.square(img[1][y][x])) >= escape: + z[y][x] = i + + +#meshgrid makes things slower as we can't test individual points for breaking to infinity; +#however, I will fix that later. +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +with alive_bar(img_res_y, bar = 'filling', spinner = 'waves') as bar: + for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + completed_ratio = (((pix_x * pix_y * 1)) / total_pixels) + next_x = on_x/np.sin(on_y) + on_y = on_y/np.sin(on_x) + on_x = next_x + + + # do physics here - we could just use vectors but i keep rewriting things + timesteps = max_ + acceleration = np.array([0, 0], dtype=np.double) + velocity = np.array([on_x, on_y], dtype=np.double) # maybe multiply by stuff + pos = np.array([0,0], dtype=np.double) + for t in range(timesteps): + for p in point_charges: + acceleration += p.get_field(on_x, on_y) + velocity += acceleration + pos += velocity * (timesteps) + on_x += pos[0] + on_y += pos[1] + + if on_x**2 + on_y**2 > escape: + image[pix_x][pix_y] = i + break + bar() + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +plt.show() + + +# yeah, I shouldn't have switched to a meshgrid, oh well +#z = np.empty_like(image[0]) +exit(0) +with alive_bar(img_res_x, bar = 'filling', spinner = 'waves') as bar: + for y in range(img_res_y): + for x in range(img_res_x): + for i in range(iterations): + if image[0][y][x] == np.NAN: + continue + next_x = image[1][y][x] / np.sin(image[0][y][x]) + image[0][y][x] = image[0][y][x] / np.sin(image[1][y][x]) + image[1][y][x] = next_x + if (np.square(image[0][y][x]) + np.square(image[1][y][x])) >= escape: + z[y][x] = i + image[0][y][x] = np.NAN + image[1][y][x] = np.NAN + break +# #do physics here + + + + bar() +#image = np.clip(image, -escape, escape) + diff --git a/field_tests/gpu_migration.py b/field_tests/gpu_migration.py new file mode 100755 index 0000000..718fe7d --- /dev/null +++ b/field_tests/gpu_migration.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +x_min = (-periods * np.pi) + (square_x * np.pi) +x_max = (periods * np.pi) + (square_x * np.pi) +y_min = (-periods * np.pi) + (square_y * np.pi) +y_max = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +#ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +bruh = None + +def on_click(event): + global bruh + split_ratio = 1 + if (event.button is MouseButton.MIDDLE) and (event.inaxes): + # there's probably a way to set global coordinates; + # I don't expect this to go anywhere so I don't really care + on_x = ((event.xdata / img_res_x) * abs(x_max - x_min)) + x_min + on_y = ((event.ydata / img_res_y) * abs(y_max - y_min)) + y_min + + #I, uh, also don't know the best way to replicate the openCL code automaticly in python + #so ajust if nessesary + x_hops = [] + y_hops = [] + for i in range(iterations): + x_hops.append(((on_x - x_min) / abs(x_max - x_min)) * img_res_x) + y_hops.append(((on_y - y_min) / abs(y_max - y_min)) * img_res_y) + next_x = on_x/np.tan(on_y) + on_y = on_y/np.tan(on_x) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + print(y_hops[0]) + print(on_y) + print("{} hops".format(len(x_hops))) + if bruh: + bruh.pop(0).remove() + bruh = ax.plot(x_hops, y_hops) + plt.draw() + + + + print(on_x, on_y) + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + + + +print("Rendering {} frames...".format(frames)) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + ax.imshow(image, norm="log", aspect="auto", cmap=cmap) + fig.savefig(single_frame_save) + plt.autoscale(False) + plt.connect('motion_notify_event', on_click) + plt.show() + + diff --git a/field_tests/kernel.c b/field_tests/kernel.c new file mode 100644 index 0000000..08b9137 --- /dev/null +++ b/field_tests/kernel.c @@ -0,0 +1,26 @@ +__kernel void basic_test() { + printf("this cores ID: (%lu, %lu)\n", get_global_id(0), get_global_id(1)); +} + +__kernel void render_frame(__global unsigned int *frame_output, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double on_x = (get_global_id(0) * x_step) + x_start; + double on_y = (get_global_id(1) * y_step) + y_start; + double next_x; + unsigned int iter; + + orig_x = on_x; + orig_y = on_y; + for(iter = 0; iter < iterations; iter++) { + if(orig_x == 123 && orig_y == 5) printf("%d, %d\n", orig_x,orig_y); + next_x = on_x / sin(on_y); + on_y = on_y / sin(on_x); + on_x = next_x; + if((pow(on_x, 2) + pow(on_y, 2)) >= escape) break; + } + + frame_output[(get_global_id(1) * get_global_size(1)) + get_global_id(0)] = iter; +} diff --git a/field_tests/makefile b/field_tests/makefile new file mode 100644 index 0000000..539deb1 --- /dev/null +++ b/field_tests/makefile @@ -0,0 +1,4 @@ +make: + gcc -Wall -fpic -c field.c + gcc -Wall -shared -o field.so field.o + python3 field.py diff --git a/linear_transform_test.py b/linear_transform_test.py new file mode 100755 index 0000000..5a0afca --- /dev/null +++ b/linear_transform_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +from alive_progress import alive_bar + +img_res_x = 500 +img_res_y = 500 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = .25 +square_x = 1 +square_y = 1 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + + +image = np.empty([img_res_y, img_res_x]) + +with alive_bar(img_res_y, bar = 'filling', spinner = 'waves') as bar: + for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + completed_ratio = ((pix_y * img_res_y) + pix_x) / total_pixels + next_x = (completed_ratio * (on_x/np.sin(on_y))) + ((1 - completed_ratio) * on_x/np.tan(on_y)) + on_y = (completed_ratio * (on_y/np.sin(on_x))) + ((1 - completed_ratio) * on_y/np.tan(on_x)) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + print(completed_ratio) + image[pix_y][pix_x] = i + bar() + + + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +fig.savefig("linear_transform_sin_tan_arnolds_tongue_hotspot.png") +plt.show() diff --git a/live_play/.gpu_migration.py.swo b/live_play/.gpu_migration.py.swo Binary files differnew file mode 100644 index 0000000..4806821 --- /dev/null +++ b/live_play/.gpu_migration.py.swo diff --git a/live_play/.gpu_migration.py.swp b/live_play/.gpu_migration.py.swp Binary files differnew file mode 100644 index 0000000..29b75a7 --- /dev/null +++ b/live_play/.gpu_migration.py.swp diff --git a/live_play/.kernel.c.swp b/live_play/.kernel.c.swp Binary files differnew file mode 100644 index 0000000..6ab3a51 --- /dev/null +++ b/live_play/.kernel.c.swp diff --git a/live_play/gpu_migration.py b/live_play/gpu_migration.py new file mode 100755 index 0000000..4269bcc --- /dev/null +++ b/live_play/gpu_migration.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import matplotlib.style as mplstyle +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton +from PIL import Image + +# HELLO READER ------------------------------------------------------------------------ +# yes, I know this script is horrid, but it's more of a scratchpad to quickly test ideas +# and not anything I'm ever going to show anyone else. + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = -2 + +escape = 10000 +iterations = (255*3)*2 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) + +#ax.invert_yaxis() +ax.set_xlim((-periods * np.pi) + (square_x * np.pi), (periods * np.pi) + (square_x * np.pi)) +ax.set_ylim((-periods * np.pi) + (square_y * np.pi), (periods * np.pi) + (square_y * np.pi)) + +#ax.set_axis_off() +fig.add_axes(ax) +mplstyle.use('fast') + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + + + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + +temp_render_hook = False +mp_image = None + +def render(axes): + global temp_render_hook + global mp_image + if not temp_render_hook: + temp_render_hook = True + x_min = axes.get_xlim()[0] + x_max = axes.get_xlim()[1] + y_min = axes.get_ylim()[1] + y_max = axes.get_ylim()[0] + print(axes.get_ylim()) + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, mask_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + print("kernel") + if mp_image == None: + mp_image = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, interpolation='none', extent=(x_min, x_max, y_min, y_max)) # TODO + else: + mp_image.set(extent=(x_min, x_max, y_min, y_max)) + #ax.set_aspect('equal') + #mp_image.set_data(image) + mp_image.set_array(image) + + + fig.canvas.draw_idle() + fig.canvas.flush_events() + temp_render_hook = False + +#plt.ion() + +#open image +mask_path = "mask.png" +mask = np.asarray(Image.open(mask_path).convert("L").resize((img_res_x, img_res_y)), dtype=np.double) +#mask = np.zeros((1000, 1000), dtype=np.double) +mask.setflags(write=1) +mask /= np.max(mask) # normalize +print(mask.shape) +print(mask.dtype) +print(mask) +#ax.imshow(mask, norm="linear") +#plt.show() + +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) +mask_buffer = cl.Buffer(opencl_context, cl.mem_flags.READ_ONLY, mask.nbytes) +cl.enqueue_copy(opencl_queue, mask_buffer, mask).wait() +#mask_buffer = cl.array.Array(opencl_context,mask.shape, dtype=np.uint8, data=mask) + +#move to render +print("Rendering {} frames...".format(frames)) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, mask, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + ax.callbacks.connect('ylim_changed', render) + ax.callbacks.connect('xlim_changed', render) + render(ax) + plt.show(block=True) + + diff --git a/live_play/kernel.c b/live_play/kernel.c new file mode 100644 index 0000000..e572a48 --- /dev/null +++ b/live_play/kernel.c @@ -0,0 +1,40 @@ +//#include <math.h> +#define PI 3.141592653589793115997963468544185161590576171875 + +double cosecant_single(double a, double b) { return a / sin(b); } +double secant_single(double a, double b) { + //double killme = (double)floor(b / (PI / 2.0)) * (double)(PI / 2.0); + //return a / sin(killme); + //return a / sin((PI / 2.0)); + //return a / sin(PI); + return a / sin(-PI); +} + + +__kernel void render_frame(__global unsigned int *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double x = (get_global_id(0) * x_step) + x_start; + double y = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + unsigned int iter; + + + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = mask[img_index]; + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + + + frame_output[img_index] = iter; + //frame_output[img_index] = mask[img_index] * 255; +} diff --git a/live_play/mask.png b/live_play/mask.png new file mode 120000 index 0000000..5209b4e --- /dev/null +++ b/live_play/mask.png @@ -0,0 +1 @@ +../masks/threedots.png
\ No newline at end of file diff --git a/live_play/notes b/live_play/notes new file mode 100644 index 0000000..50249d7 --- /dev/null +++ b/live_play/notes @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar + +img_res_x = 2000 +img_res_y = 2000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "./animations" +frames = 120 + +rendered_frames = [] + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +opencl_context = cl.create_some_context() +opencl_queue = cl.CommandQueue(opencl_context) + + +#def render(): +# image = np.empty([img_res_y, img_res_x]) +# print("Rendering frames") +# with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: +# for frame in range(frames): +# split_ratio = frame / frames +# for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): +# for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): +# on_x = x +# on_y = y +# for i in range(iterations): +# next_x = (split_ratio * (on_x/np.sin(on_y))) + ((1 - split_ratio) * on_x/np.tan(on_y)) +# on_y = (split_ratio * (on_y/np.sin(on_x))) + ((1 - split_ratio) * on_y/np.tan(on_x)) +# on_x = next_x +# if on_x**2 + on_y**2 > escape: +# break +# image[pix_y][pix_x] = i +# rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated=False) +# rendered_frames.append([rendered_frame]) +# bar_total() + +def display(): + print(rendered_frames) + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save("test.mp4") + plt.show() + +render() +display() diff --git a/mask_tests/; b/mask_tests/; new file mode 100644 index 0000000..665c6ce --- /dev/null +++ b/mask_tests/; @@ -0,0 +1,30 @@ +unsigned int secant_fractal(double x, double y, unsigned int escape, unsigned int iterations) { + for(unsigned int iter = 0; iter < iterations; iter++) { + double next_x; + next_x = x / cos(y); + y = y / cos(x); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) return iter; + } +} +unsigned int cosecant_fractal(double x, double y, unsigned int escape, unsigned int iterations) { + for(unsigned int iter = 0; iter < iterations; iter++) { + double next_x; + next_x = x / sin(y); + y = y / sin(x); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) return iter; + } +} + +__kernel void render_frame(__global unsigned int *frame_output, //uint8_t *mask, //more bit depth is possible + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double on_x = (get_global_id(0) * x_step) + x_start; + double on_y = (get_global_id(1) * y_step) + y_start; + + frame_output[(get_global_id(1) * get_global_size(1)) + get_global_id(0)] = + secant_fractal(on_x, on_y, escape, iterations); +} diff --git a/mask_tests/asdf.png b/mask_tests/asdf.png Binary files differnew file mode 100644 index 0000000..66d8a87 --- /dev/null +++ b/mask_tests/asdf.png diff --git a/mask_tests/kernel.c b/mask_tests/kernel.c new file mode 100644 index 0000000..669c382 --- /dev/null +++ b/mask_tests/kernel.c @@ -0,0 +1,49 @@ +unsigned int secant_fractal(double x, double y, unsigned int escape, unsigned int iterations) { + for(unsigned int iter = 0; iter < iterations; iter++) { + double next_x; + next_x = x / cos(y); + y = y / cos(x); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) return iter; + } +} +unsigned int cosecant_fractal(double x, double y, unsigned int escape, unsigned int iterations) { + for(unsigned int iter = 0; iter < iterations; iter++) { + double next_x; + next_x = x / sin(y); + y = y / sin(x); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) return iter; + } +} + +double cosecant_single(double a, double b) { return a / sin(b); } +double secant_single(double a, double b) { return a / tan(b); } + + +__kernel void render_frame(__global unsigned int *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double x = (get_global_id(0) * x_step) + x_start; + double y = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + unsigned int iter; + + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = mask[img_index]; + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + + + frame_output[img_index] = iter; + //frame_output[img_index] = mask[img_index] * 255; +} diff --git a/mask_tests/mask.png b/mask_tests/mask.png new file mode 120000 index 0000000..5209b4e --- /dev/null +++ b/mask_tests/mask.png @@ -0,0 +1 @@ +../masks/threedots.png
\ No newline at end of file diff --git a/mask_tests/mask.py b/mask_tests/mask.py new file mode 100755 index 0000000..ee801d4 --- /dev/null +++ b/mask_tests/mask.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton +from PIL import Image + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +x_min = (-periods * np.pi) + (square_x * np.pi) +x_max = (periods * np.pi) + (square_x * np.pi) +y_min = (-periods * np.pi) + (square_y * np.pi) +y_max = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +#ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +mask_path = "mask.png" + +bruh = None + +def on_click(event): + global bruh + split_ratio = 1 + if (event.button is MouseButton.MIDDLE) and (event.inaxes): + # there's probably a way to set global coordinates; + # I don't expect this to go anywhere so I don't really care + on_x = ((event.xdata / img_res_x) * abs(x_max - x_min)) + x_min + on_y = ((event.ydata / img_res_y) * abs(y_max - y_min)) + y_min + + #I, uh, also don't know the best way to replicate the openCL code automaticly in python + #so ajust if nessesary + x_hops = [] + y_hops = [] + for i in range(iterations): + x_hops.append(((on_x - x_min) / abs(x_max - x_min)) * img_res_x) + y_hops.append(((on_y - y_min) / abs(y_max - y_min)) * img_res_y) + next_x = on_x/np.tan(on_y) + on_y = on_y/np.tan(on_x) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + print(y_hops[0]) + print(on_y) + print("{} hops".format(len(x_hops))) + if bruh: + bruh.pop(0).remove() + bruh = ax.plot(x_hops, y_hops) + plt.draw() + + + + print(on_x, on_y) + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + +#open image +mask = np.asarray(Image.open(mask_path).convert("L"), dtype=np.double) +mask.setflags(write=1) +mask /= np.max(mask) # normalize +print(mask.shape) +print(mask.dtype) +#ax.imshow(mask, norm="linear") +#plt.show() + +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) +mask_buffer = cl.Buffer(opencl_context, cl.mem_flags.READ_ONLY, mask.nbytes) +cl.enqueue_copy(opencl_queue, mask_buffer, mask).wait() +#mask_buffer = cl.array.Array(opencl_context,mask.shape, dtype=np.uint8, data=mask) + + + + +# TODO clean this up +print("Rendering {} frames...".format(frames)) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, mask_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + ax.imshow(image, norm="log", aspect="auto", cmap=cmap) + fig.savefig(single_frame_save) + plt.autoscale(False) + plt.connect('motion_notify_event', on_click) + plt.show() diff --git a/mask_tests/mask.py.bak b/mask_tests/mask.py.bak new file mode 100644 index 0000000..8fd3513 --- /dev/null +++ b/mask_tests/mask.py.bak @@ -0,0 +1,142 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton +from PIL import Image + +img_res_x = 1000 +img_res_y = 1000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +x_min = (-periods * np.pi) + (square_x * np.pi) +x_max = (periods * np.pi) + (square_x * np.pi) +y_min = (-periods * np.pi) + (square_y * np.pi) +y_max = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +#ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +mask_path = "mask.png" + +bruh = None + +def on_click(event): + global bruh + split_ratio = 1 + if (event.button is MouseButton.MIDDLE) and (event.inaxes): + # there's probably a way to set global coordinates; + # I don't expect this to go anywhere so I don't really care + on_x = ((event.xdata / img_res_x) * abs(x_max - x_min)) + x_min + on_y = ((event.ydata / img_res_y) * abs(y_max - y_min)) + y_min + + #I, uh, also don't know the best way to replicate the openCL code automaticly in python + #so ajust if nessesary + x_hops = [] + y_hops = [] + for i in range(iterations): + x_hops.append(((on_x - x_min) / abs(x_max - x_min)) * img_res_x) + y_hops.append(((on_y - y_min) / abs(y_max - y_min)) * img_res_y) + next_x = on_x/np.tan(on_y) + on_y = on_y/np.tan(on_x) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + print(y_hops[0]) + print(on_y) + print("{} hops".format(len(x_hops))) + if bruh: + bruh.pop(0).remove() + bruh = ax.plot(x_hops, y_hops) + plt.draw() + + + + print(on_x, on_y) + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + +with open G + + +# TODO clean this up +print("Rendering {} frames...".format(frames)) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + ax.imshow(image, norm="log", aspect="auto", cmap=cmap) + fig.savefig(single_frame_save) + plt.autoscale(False) + plt.connect('motion_notify_event', on_click) + plt.show() + + diff --git a/mask_tests/notes b/mask_tests/notes new file mode 100644 index 0000000..50249d7 --- /dev/null +++ b/mask_tests/notes @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar + +img_res_x = 2000 +img_res_y = 2000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "./animations" +frames = 120 + +rendered_frames = [] + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +opencl_context = cl.create_some_context() +opencl_queue = cl.CommandQueue(opencl_context) + + +#def render(): +# image = np.empty([img_res_y, img_res_x]) +# print("Rendering frames") +# with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: +# for frame in range(frames): +# split_ratio = frame / frames +# for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): +# for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): +# on_x = x +# on_y = y +# for i in range(iterations): +# next_x = (split_ratio * (on_x/np.sin(on_y))) + ((1 - split_ratio) * on_x/np.tan(on_y)) +# on_y = (split_ratio * (on_y/np.sin(on_x))) + ((1 - split_ratio) * on_y/np.tan(on_x)) +# on_x = next_x +# if on_x**2 + on_y**2 > escape: +# break +# image[pix_y][pix_x] = i +# rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated=False) +# rendered_frames.append([rendered_frame]) +# bar_total() + +def display(): + print(rendered_frames) + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save("test.mp4") + plt.show() + +render() +display() diff --git a/masks/clouds.png b/masks/clouds.png Binary files differnew file mode 100644 index 0000000..d57cade --- /dev/null +++ b/masks/clouds.png diff --git a/masks/hi.png b/masks/hi.png Binary files differnew file mode 100644 index 0000000..f565075 --- /dev/null +++ b/masks/hi.png diff --git a/masks/test_circle.png b/masks/test_circle.png Binary files differnew file mode 100644 index 0000000..a52b528 --- /dev/null +++ b/masks/test_circle.png diff --git a/masks/test_circle_linear_smooth.png b/masks/test_circle_linear_smooth.png Binary files differnew file mode 100644 index 0000000..ba4687f --- /dev/null +++ b/masks/test_circle_linear_smooth.png diff --git a/masks/test_circle_perceptual_smooth.png b/masks/test_circle_perceptual_smooth.png Binary files differnew file mode 100644 index 0000000..a26d2aa --- /dev/null +++ b/masks/test_circle_perceptual_smooth.png diff --git a/masks/test_diagnol.png b/masks/test_diagnol.png Binary files differnew file mode 100644 index 0000000..270c160 --- /dev/null +++ b/masks/test_diagnol.png diff --git a/masks/test_diagnol_linear_smooth.png b/masks/test_diagnol_linear_smooth.png Binary files differnew file mode 100644 index 0000000..b9d929c --- /dev/null +++ b/masks/test_diagnol_linear_smooth.png diff --git a/masks/test_diagnol_perceptual_smooth.png b/masks/test_diagnol_perceptual_smooth.png Binary files differnew file mode 100644 index 0000000..82aa4af --- /dev/null +++ b/masks/test_diagnol_perceptual_smooth.png diff --git a/masks/threedots.png b/masks/threedots.png Binary files differnew file mode 100644 index 0000000..0d059f1 --- /dev/null +++ b/masks/threedots.png diff --git a/photos_incorrectly_named/cosine_gpu_double_2.png b/photos_incorrectly_named/cosine_gpu_double_2.png Binary files differnew file mode 100644 index 0000000..0d5ced0 --- /dev/null +++ b/photos_incorrectly_named/cosine_gpu_double_2.png diff --git a/photos_incorrectly_named/cpu.png b/photos_incorrectly_named/cpu.png Binary files differnew file mode 100644 index 0000000..ddea68c --- /dev/null +++ b/photos_incorrectly_named/cpu.png diff --git a/photos_incorrectly_named/ice_period_16.png b/photos_incorrectly_named/ice_period_16.png Binary files differnew file mode 100644 index 0000000..7d7b208 --- /dev/null +++ b/photos_incorrectly_named/ice_period_16.png diff --git a/photos_incorrectly_named/ice_period_16_shifted_.25.png b/photos_incorrectly_named/ice_period_16_shifted_.25.png Binary files differnew file mode 100644 index 0000000..9943361 --- /dev/null +++ b/photos_incorrectly_named/ice_period_16_shifted_.25.png diff --git a/photos_incorrectly_named/ice_period_16_shifted_.5.png b/photos_incorrectly_named/ice_period_16_shifted_.5.png Binary files differnew file mode 100644 index 0000000..0bb2589 --- /dev/null +++ b/photos_incorrectly_named/ice_period_16_shifted_.5.png diff --git a/photos_incorrectly_named/ice_period_noshift_x_1.png b/photos_incorrectly_named/ice_period_noshift_x_1.png Binary files differnew file mode 100644 index 0000000..3be0525 --- /dev/null +++ b/photos_incorrectly_named/ice_period_noshift_x_1.png diff --git a/photos_incorrectly_named/linear_transform_sin_tan_arnolds_tongue_hotspot.png b/photos_incorrectly_named/linear_transform_sin_tan_arnolds_tongue_hotspot.png Binary files differnew file mode 100644 index 0000000..1e5b02d --- /dev/null +++ b/photos_incorrectly_named/linear_transform_sin_tan_arnolds_tongue_hotspot.png diff --git a/polar/.gpu_migration.py.swo b/polar/.gpu_migration.py.swo Binary files differnew file mode 100644 index 0000000..4806821 --- /dev/null +++ b/polar/.gpu_migration.py.swo diff --git a/polar/.gpu_migration.py.swp b/polar/.gpu_migration.py.swp Binary files differnew file mode 100644 index 0000000..29b75a7 --- /dev/null +++ b/polar/.gpu_migration.py.swp diff --git a/polar/.kernel.c.swp b/polar/.kernel.c.swp Binary files differnew file mode 100644 index 0000000..6ab3a51 --- /dev/null +++ b/polar/.kernel.c.swp diff --git a/polar/gpu_migration.py b/polar/gpu_migration.py new file mode 100755 index 0000000..1a8af19 --- /dev/null +++ b/polar/gpu_migration.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import matplotlib.style as mplstyle +import pyopencl as cl +from alive_progress import alive_bar +from matplotlib.backend_bases import MouseButton +from PIL import Image + +# HELLO READER ------------------------------------------------------------------------ +# yes, I know this script is horrid, but it's more of a scratchpad to quickly test ideas +# and not anything I'm ever going to show anyone else. + +img_res_x = 10000 +img_res_y = 10000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = -2 + +escape = 10000 +iterations = (255*3) +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "ani1_less.mp4" +single_frame_save = "asdf.png" + +opencl_context = cl.create_some_context(interactive=False) +opencl_queue = cl.CommandQueue(opencl_context) + +kernel_src_path = "./kernel.c" + +frames = 1 +rendered_frames = [] + +image = np.empty([img_res_x, img_res_y], np.uint32) + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + + +ax = plt.Axes(fig, [0., 0., 1., 1.]) + +#ax.invert_yaxis() +#ax.set_xlim((-periods * np.pi) + (square_x * np.pi), (periods * np.pi) + (square_x * np.pi)) +#ax.set_ylim((-periods * np.pi) + (square_y * np.pi), (periods * np.pi) + (square_y * np.pi)) +ax.set_xlim(-6.678564587410841, -4.837591292407222) +ax.set_ylim(-1.0818908008385455, 0.9287284974589227) + +#ax.set_axis_off() +fig.add_axes(ax) +mplstyle.use('fast') + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + + + + +print("compiling openCL kernel...") +with open(kernel_src_path, 'r') as kernel_src: + compiled_kernel = cl.Program(opencl_context, kernel_src.read()).build() + +encoding_progress = alive_bar(frames, bar = 'filling', spinner = 'waves') + +def display_encoder_progress(current_frame: int, total_frames: int): + print("Encoding: frame {}/{}".format(current_frame, frames)) + +temp_render_hook = False +mp_image = None + +def render(axes): + global temp_render_hook + global mp_image + if not temp_render_hook: + temp_render_hook = True + x_min = axes.get_xlim()[0] + x_max = axes.get_xlim()[1] + y_min = axes.get_ylim()[1] + y_max = axes.get_ylim()[0] + print(axes.get_ylim()) + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, mask_buffer, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(1)) + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + print("kernel") + if mp_image == None: + mp_image = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, interpolation='none', extent=(x_min, x_max, y_min, y_max)) # TODO + else: + mp_image.set(extent=(x_min, x_max, y_min, y_max)) + #ax.set_aspect('equal') + #mp_image.set_data(image) + mp_image.set_array(image) + + + fig.canvas.draw_idle() + fig.canvas.flush_events() + temp_render_hook = False + +#plt.ion() + +#open image +mask_path = "mask.png" +mask = np.asarray(Image.open(mask_path).convert("L").resize((img_res_x, img_res_y)), dtype=np.double) +#mask = np.zeros((img_res_x, img_res_y), dtype=np.double) +mask.setflags(write=1) +mask /= np.max(mask) # normalize +print(mask.shape) +print(mask.dtype) +print(mask) +#ax.imshow(mask, norm="linear") +#plt.show() + +image_buffer = cl.Buffer(opencl_context, cl.mem_flags.WRITE_ONLY, image.nbytes) +mask_buffer = cl.Buffer(opencl_context, cl.mem_flags.READ_ONLY, mask.nbytes) +cl.enqueue_copy(opencl_queue, mask_buffer, mask).wait() +#mask_buffer = cl.array.Array(opencl_context,mask.shape, dtype=np.uint8, data=mask) + +#move to render +print("Rendering {} frames...".format(frames)) +if frames > 1: + with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: + for frame_i in range(0, frames): + compiled_kernel.render_frame(opencl_queue, image.shape, None, image_buffer, mask, + np.double(abs(x_max - x_min) / img_res_x), + np.double(abs(y_max - y_min) / img_res_y), + np.double(x_min), np.double(y_min), + np.uint32(iterations), np.uint32(escape), + np.double(frame_i / frames)) + + + cl.enqueue_copy(opencl_queue, image, image_buffer).wait() + rendered_frame = ax.imshow(image, norm="linear", aspect="auto", cmap=cmap, animated="True") + rendered_frames.append([rendered_frame]) + bar_total() + print("Encoding/Saving...") + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save(animation_progres_save, extra_args=['-preset', 'lossless'], progress_callback=display_encoder_progress, codec="h264_nvenc") +else: + ax.callbacks.connect('ylim_changed', render) + ax.callbacks.connect('xlim_changed', render) + render(ax) + plt.savefig("out.png") + #plt.show(block=True) + + diff --git a/polar/kernel.c b/polar/kernel.c new file mode 100644 index 0000000..1369a7f --- /dev/null +++ b/polar/kernel.c @@ -0,0 +1,35 @@ +//#include <math.h> +#define PI 3.141592653589793115997963468544185161590576171875 + +double cosecant_single(double a, double b) { return a / sin(b); } +double secant_single(double a, double b) { return a / tan(b); } + + +__kernel void render_frame(__global unsigned int *frame_output, __global double *mask, + double x_step, double y_step, + double x_start, double y_start, + unsigned int iterations, unsigned int escape, double ratio) { + unsigned int result; + double x_cart = (get_global_id(0) * x_step) + x_start; + double y_cart = (get_global_id(1) * y_step) + y_start; + size_t img_index = (get_global_id(1) * get_global_size(1)) + get_global_id(0); + + double x = sqrt(pow(x_cart, 2) + pow(y_cart, 2)); + double y = atan(y_cart / x_cart); + + unsigned int iter; + + for(iter = 0; iter < iterations; iter++) { + double next_x; + double r = mask[img_index]; + next_x = (r * cosecant_single(x, y)) + ((1 - r) * secant_single(x, y)); + y = (r * cosecant_single(y, x)) + ((1 - r) * secant_single(y, x)); + x = next_x; + if((pow(x, 2) + pow(y, 2)) >= escape) break; + } + + + + frame_output[img_index] = iter; + //frame_output[img_index] = mask[img_index] * 255; +} diff --git a/polar/notes b/polar/notes new file mode 100644 index 0000000..50249d7 --- /dev/null +++ b/polar/notes @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import pyopencl as cl +from alive_progress import alive_bar + +img_res_x = 2000 +img_res_y = 2000 +total_pixels = img_res_x * img_res_y # so we don't gotta compute it every time + +periods = 1 +square_x = 0 +square_y = 0 + +xmin = (-periods * np.pi) + (square_x * np.pi) +xmax = (periods * np.pi) + (square_x * np.pi) +ymin = (-periods * np.pi) + (square_y * np.pi) +ymax = (periods * np.pi) + (square_y * np.pi) + +escape = 10000 +iterations = 255*3 +c_x = 2 * np.pi +c_y = 2 * np.pi + +animation_progres_save = "./animations" +frames = 120 + +rendered_frames = [] + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +opencl_context = cl.create_some_context() +opencl_queue = cl.CommandQueue(opencl_context) + + +#def render(): +# image = np.empty([img_res_y, img_res_x]) +# print("Rendering frames") +# with alive_bar(frames, bar = 'filling', spinner = 'waves') as bar_total: +# for frame in range(frames): +# split_ratio = frame / frames +# for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): +# for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): +# on_x = x +# on_y = y +# for i in range(iterations): +# next_x = (split_ratio * (on_x/np.sin(on_y))) + ((1 - split_ratio) * on_x/np.tan(on_y)) +# on_y = (split_ratio * (on_y/np.sin(on_x))) + ((1 - split_ratio) * on_y/np.tan(on_x)) +# on_x = next_x +# if on_x**2 + on_y**2 > escape: +# break +# image[pix_y][pix_x] = i +# rendered_frame = ax.imshow(image, norm="log", aspect="auto", cmap=cmap, animated=False) +# rendered_frames.append([rendered_frame]) +# bar_total() + +def display(): + print(rendered_frames) + ani = animation.ArtistAnimation(fig, rendered_frames, interval=30, blit=True) + ani.save("test.mp4") + plt.show() + +render() +display() diff --git a/polar/texput.log b/polar/texput.log new file mode 100644 index 0000000..d13b81a --- /dev/null +++ b/polar/texput.log @@ -0,0 +1,21 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.26 (TeX Live 2024/Arch Linux) (preloaded format=pdflatex 2024.4.22) 28 APR 2024 21:33 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +** + +! Emergency stop. +<*> + +End of file on the terminal! + + +Here is how much of TeX's memory you used: + 3 strings out of 476076 + 113 string characters out of 5793775 + 1925187 words of memory out of 5000000 + 22212 multiletter control sequences out of 15000+600000 + 558069 words of font info for 36 fonts, out of 8000000 for 9000 + 14 hyphenation exceptions out of 8191 + 0i,0n,0p,13b,6s stack positions out of 10000i,1000n,20000p,200000b,200000s +! ==> Fatal error occurred, no output PDF file produced! diff --git a/thorn_fractal.py b/thorn_fractal.py new file mode 100755 index 0000000..ed0e431 --- /dev/null +++ b/thorn_fractal.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +import numpy as np +import matplotlib.pyplot as plt + +img_res_x = 2000 +img_res_y = 2000 + +xmin = -np.pi +xmax = np.pi +ymin = -np.pi +ymax = np.pi + +escape = 10000 +iterations = 255 +c_x = 0 +c_y = 0 + + +image = np.empty([img_res_y, img_res_x], np.float32) + +for pix_y, y in enumerate(np.linspace(ymin, ymax, img_res_y)): + for pix_x, x in enumerate(np.linspace(xmin, xmax, img_res_x)): + on_x = x + on_y = y + for i in range(iterations): + next_x = (on_x/np.sin(on_y)) + on_y = (on_y/np.sin(on_x)) + on_x = next_x + if on_x**2 + on_y**2 > escape: + break + image[pix_y][pix_x] = i + #print(pix_y) + + + + +plt.style.use('dark_background') +# fuck this shit +fig = plt.figure(frameon=False) +fig.set_size_inches(img_res_x/fig.dpi, img_res_y/fig.dpi) +#fig.set_size_inches(width/height, 1, forward=False) +print(fig.dpi) + +ax = plt.Axes(fig, [0., 0., 1., 1.]) +ax.set_axis_off() +fig.add_axes(ax) + +cmap = plt.cm.viridis +cmap.set_bad((0,0,0)) +cmap.set_over((0,0,0)) +cmap.set_under((0,0,0)) + +ax.imshow(image, norm="log", aspect="auto", cmap=cmap) +fig.savefig("animation/cpu.png") +#plt.show() |