๐Ÿ๐Ÿ๐Ÿ

example images; image save perf. improvements

autumn c0fe8d92 03fd01db

+105 -102
+1
.gitignore
··· 1 1 .git 2 2 __pycache__ 3 3 out 4 + scratch.py
+41 -61
abelian_sandpile.py
··· 1 1 import math 2 2 import random 3 + import time 4 + from pathlib import Path 3 5 4 6 import torch 5 7 6 8 from util import * 7 9 8 10 @settings 9 - def _settings(): 11 + def _s(): 10 12 scale = 2 ** 10 11 13 w = scale + 1 12 14 h = scale + 1 ··· 14 16 iterations = 500000 15 17 debug_modulus = 10000 16 18 17 - out_file = "hng" 19 + offsets = [[-n,0] for n in range(17)] + [[n,0] for n in range(17)] + [[0,17]] 20 + drop_points = [[h//2,w//2+n] for n in range(17)] 21 + 22 + wrap_vertical = False 23 + wrap_horizontal = True 24 + 25 + name = "sand" 26 + out_file = "" 18 27 19 28 device="cuda" 20 29 ctype=torch.cdouble 21 30 dtype=torch.double 22 31 23 - @ifmain(__name__) 32 + @ifmain(__name__, _s) 24 33 @timed 25 - def _main(): 26 - _ = _settings() 27 - torch.set_default_device(_.device) 28 - torch.set_default_dtype(_.dtype) 29 - dim = [_.h, _.w] 34 + def _main(settings): 35 + globals().update(settings.get()) 36 + run_dir = time.strftime(f"%d.%m.%Y/{name}_t%H.%M.%S") 37 + Path("out/" + run_dir).mkdir(parents=True, exist_ok=True) 38 + with open(f"out/{run_dir}/settings.py", "w") as f: 39 + f.write(settings.src) 40 + torch.set_default_device(device) 41 + torch.set_default_dtype(dtype) 42 + dim = [h, w] 30 43 31 44 grid = torch.zeros(dim, dtype=torch.int) 32 45 33 - #offsets = [torch.tensor(x) for x in [[0,1],[0,-1],[1,0],[-1,0]]] 34 - #offsets = [[1,1],[1,-1],[-1,1],[-1,-1],[0,2],[0,-2],[2,0],[-2,0]] 35 - #offsets = [[0,10],[10,0],[5,10],[10,5],[5,5],[-1,0],[0,-1]] 36 - #offsets = [[0,5],[5,0],[0,-5],[-5,0],[1,4],[4,1],[-1,4],[4,-1],[1,-4],[-4,1],[-4,-1],[-1,-4]] 37 - offsets = [[0,3],[3,0],[1,2],[2,1],[13,3],[3,13],[1,0],[0,1],[1,1],[0,0]] 38 - #offsets = [x for x in [ 39 - # [1,1], 40 - # [0,1], 41 - # [1,0], 42 - # [0,-5], 43 - # [-5,-5], 44 - # [-5,0] 45 - # ]] 46 - 47 - max_c = 100 46 + max_c = 500 48 47 c_total = 0 49 - last_c_total = 100 48 + last_c_total = 500 50 49 51 50 n = len(offsets) 52 51 53 - for iteration in range(_.iterations): 54 - #spots = torch.randn(dim) > 2.5 55 - #grid += spots 56 - #p = [_.h // 2, _.w // 2] 57 - p = [0,0] 58 - #p = [random.randint(0,_.h-1), random.randint(0,_.w-1)] 52 + for iteration in range(iterations): 59 53 last = torch.clone(grid) 60 - grid[p[0],p[1]] = n 54 + for p in drop_points: 55 + #grid[p[0],p[1]] += 1 56 + grid[p[0],p[1]] = n 57 + # todo: make this index_put_ 61 58 peaks = (grid >= n).int() 62 - #peaks = torch.nonzero(grid >= 4) 63 59 c = 0 64 60 while torch.count_nonzero(peaks): 65 - #while len(peaks) != 0: 66 61 c += 1 67 - #p0 = peaks[0] 68 - #pts = [p0 + o for o in offsets] 69 - #pts = [p for p in pts if 0 < p[0] < _.h and 0 < p[1] < _.w] 70 - #for p in pts: 71 - # grid[p[0],p[1]] += 1 72 - #grid[p0[0],p0[1]] -= 4 62 + 73 63 shift = -(n * peaks) 74 64 for offset in offsets: 75 65 p_shift = torch.roll(peaks, offset, dims=[0,1]) 76 - if offset[0] < 0: 66 + if offset[0] < 0 and not wrap_vertical: 77 67 p_shift[offset[0]:] = 0 78 - else: 68 + elif not wrap_vertical: 79 69 p_shift[:offset[0]] = 0 80 - if offset[1] < 0: 70 + if offset[1] < 0 and not wrap_horizontal: 81 71 p_shift[:,offset[1]:] = 0 82 - else: 72 + elif not wrap_horizontal: 83 73 p_shift[:,:offset[1]] = 0 84 74 shift += p_shift 85 75 grid += shift 86 76 87 - #pa = torch.roll(peaks, 1, dims=0) 88 - #pb = torch.roll(peaks, -1, dims=0) 89 - #pc = torch.roll(peaks, 1, dims=1) 90 - #pd = torch.roll(peaks, -1, dims=1) 91 - #pa[0] = 0 92 - #pb[-1] = 0 93 - #pc[:,0] = 0 94 - #pd[:,-1] = 0 95 - #shift = pa + pb + pc + pd - (4 * peaks) 96 - #grid += shift 97 77 98 78 peaks = (grid >= n).int() 99 - #peaks = torch.nonzero(grid >= 4) 100 79 c_total += c 101 80 if c > 20: 102 81 s = "*" if c >= max_c else "" 103 82 print(f"{iteration}: {c}{s}") 104 - if c > (0.9 * max_c): 105 - msave(grid / (n-1), f"{_.out_file}_{iteration}_{c}") 106 - msave(last / (n-1), f"{_.out_file}_{iteration}_prev") 83 + if c > (0.98 * max_c): 84 + msave(grid / (n-1), f"{run_dir}/{out_file}_{iteration}_{c}") 85 + msave(last / (n-1), f"{run_dir}/{out_file}_{iteration}_prev") 107 86 if c > max_c: 108 87 max_c = c 109 - if iteration % _.debug_modulus == 0: 110 - msave(grid / (n-1), f"{_.out_file}_{iteration}_") 88 + if iteration % debug_modulus == 0: 89 + msave(grid / (n-1), f"{run_dir}/{out_file}_{iteration}_") 111 90 if c_total > (last_c_total * 2): 112 - msave(grid / (n-1), f"{_.out_file}_{iteration}_ct{c_total}") 91 + msave(grid / (n-1), f"{run_dir}/{out_file}_{iteration}_ct{c_total}") 113 92 last_c_total = c_total 114 93 115 - msave(grid / (n-1), _.out_file) 94 + msave(grid / (n-1), out_file) 95 +
examples/fluid.png

This is a binary file and will not be displayed.

examples/julia_q.png

This is a binary file and will not be displayed.

examples/ship.png

This is a binary file and will not be displayed.

examples/slime_a.png

This is a binary file and will not be displayed.

examples/slime_b.png

This is a binary file and will not be displayed.

examples/slime_c.png

This is a binary file and will not be displayed.

+12 -12
fluid.py
··· 8 8 9 9 @settings 10 10 def _s(): 11 - scale = 2**8 11 + scale = 2**11 12 12 w = scale 13 13 h = scale 14 14 15 - max_iterations = 10000 16 - save_every = 10 15 + max_iterations = 100000 16 + save_every = 100 17 17 18 18 v_diffusion_rate = 2000 19 19 m_diffusion_rate = 0.5 20 - m_timescale = 0.1 21 - timescale = 0.01 20 + m_timescale = 0.01 21 + timescale = 0.001 22 22 23 23 name = "fluid" 24 24 ··· 132 132 133 133 #velocities = torch.zeros([2, h, w]) 134 134 upsample = torch.nn.Upsample(size=[h, w], mode='bilinear') 135 - velocities = torch.randn([2, h//32, w//32]) * 100 135 + velocities = torch.randn([2, h//32, w//32]) * 1 #* 100 136 136 densities = torch.ones([1, h, w]) * 0.1 137 137 138 138 cg = cgrid(h, w, 0 + 0j, 4 + 4j, dtype=torch.float, ctype=torch.cfloat) ··· 165 165 border_mask[:,1:h-1,1:w-1] = 0; 166 166 167 167 for iteration in range(max_iterations): 168 - velocities[0,3 * h//4 - 10:(3*h//4),w//2-10:w//2+10] = -100 169 - velocities[1,3 * h//4:(3*h//4)+10,w//2-10:w//2+10] = -90 170 - velocities[0,h//4:(h//4)+10,w//2-3:w//2+3] = 100 171 - velocities[1,h//4:(h//4)+10,w//2-3:w//2+3] = 200 168 + velocities[0,3 * h//4 - 10:(3*h//4),w//2-10:w//2+10] = -10 * 40 169 + velocities[1,3 * h//4:(3*h//4)+10,w//2-10:w//2+10] = -9 * 40 170 + velocities[0,h//4:(h//4)+10,w//2-3:w//2+3] = 10 * 40 171 + velocities[1,h//4:(h//4)+10,w//2-3:w//2+3] = 20 * 40 172 172 velocities[0] += 0.01 173 - densities[0,3*h//4-10:(3*h//4),w//2-9:w//2+9] += 0.1 173 + #densities[0,3*h//4-10:(3*h//4),w//2-9:w//2+9] += 0.1 174 174 #densities[0,h//4:(h//4)+10,w//2+30:w//2+55] += 0.1 175 175 densities += 0.001 176 176 velocities[0] = diffuse(velocities[0], v_diffusion_rate, opposed_h_boundary, timescale, h, w) ··· 180 180 project(velocities, h, w) 181 181 densities = diffuse(densities[0], m_diffusion_rate, continuous_boundary, m_timescale, h, w).unsqueeze(0) 182 182 densities = advect(densities, velocities, m_timescale, h, w) 183 - densities *= 0.999 183 + densities *= 0.99 184 184 if iteration % save_every == 0: 185 185 #res = torch.cat((velocities * 0.5 + 0.5, densities), dim=0) 186 186 #save(res, f"{run_dir}/{iteration}")
+13 -13
fractal.py
··· 7 7 8 8 # Settings 9 9 10 - w = 512 * 2 10 + w = 2**13 11 11 h = w 12 12 13 13 #x_range = [-1.8, -1.7] 14 14 #y_range = [-0.095, 0.005] 15 15 16 16 #ship 17 - #x_start = -1.8 18 - #x_span = 0.1 19 - #y_start = -0.095 20 - #y_span = 0.1 17 + x_start = -1.8 18 + x_span = 0.1 19 + y_start = -0.095 20 + y_span = 0.1 21 21 22 - x_start = -math.e / 2 23 - x_span = 1.54 24 - y_start = -2 25 - y_span = 2 22 + #x_start = -math.e / 2 23 + #x_span = 1.54 24 + #y_start = -2 25 + #y_span = 2 26 26 27 27 alpha = 2.5 28 28 29 29 x_range = [x_start, x_start + x_span] 30 30 y_range = [y_start, y_start + y_span] 31 31 32 - final_file = "gauss_1" 32 + final_file = "ship_big" 33 33 34 34 device = "cuda" 35 35 ctype = torch.cfloat ··· 88 88 mask = torch.abs(z) < limit 89 89 iters = torch.zeros_like(mask, dtype=torch.uint8) 90 90 for i in range(iterations): 91 - #im = torch.abs(z.imag) * j 92 - #z = (torch.abs(z.real) + im)**2 + c_n 93 - z = torch.exp(-alpha * z) + c_n 91 + im = torch.abs(z.imag) * j 92 + z = (torch.abs(z.real) + im)**2 + c_n 93 + #z = torch.exp(-alpha * z) + c_n 94 94 95 95 if do_jitter: 96 96 z += jitter
+2 -2
raytrace.py
··· 7 7 out_file = "qjulia_11_40" 8 8 9 9 # 2**10 = 1024 10 - scale = 2 ** 11 10 + scale = 2 ** 10 11 11 w = 2 * scale // 3 12 12 h = scale 13 13 14 14 max_steps = 500 15 - mandel_iters = 20#50 15 + mandel_iters = 40#50 16 16 max_samples = 4 17 17 18 18 noise_scale = 1. / (2 * scale)
+13 -9
slime.py
··· 20 20 21 21 max_iterations = 1000 22 22 save_mod = 100 23 + also_save = [10, 50, 150] 23 24 24 - particle_count = 1000000 // 1 25 - decay_rate = 0.9 25 + particle_count = 10000000 // 4 26 + decay_rate = 0.1 26 27 27 - view_angle = tau / 8 28 - view_distance = 1.414 * 100 28 + view_angle = tau / 5 29 + view_distance = 1.414 * 140 29 30 30 - direction_count = 4 31 - turn_amount = tau / direction_count * 1.2 32 - move_distance = 1.414 * 3 31 + direction_count = 12 32 + turn_amount = tau / 6#direction_count 33 + move_distance = 1.414 * 2 33 34 34 - blur_size = 5 35 - blur_sigma = 1 35 + blur_size = 1 36 + blur_sigma = 1.5 36 37 37 38 dtype = torch.double 38 39 ctype = torch.cdouble ··· 115 116 116 117 # render 117 118 if iteration % save_mod == 0 and iteration != 0: 119 + msave(world[0], f"{run_dir}/{iteration}") 120 + 121 + if iteration in also_save: 118 122 msave(world[0], f"{run_dir}/{iteration}") 119 123 120 124 # decay
+23 -5
util.py
··· 1 1 import torch 2 + import numpy as np 2 3 from PIL import Image 4 + from safetensors.torch import save_file as sft_save 5 + import io 3 6 4 7 class Settings(dict): 5 8 __getattr__ = dict.__getitem__ ··· 55 58 cpilify(x).save(f"out/{f}.png") 56 59 57 60 # monochrome, 0 to 1 61 + def mpilify_cpu(z): 62 + _z = z.cpu().clamp_(0,1).mul_(255).round() 63 + z_np = _z.unsqueeze(2).expand(-1,-1,3).type(torch.uint8).numpy() 64 + return Image.fromarray(z_np) 65 + 58 66 def mpilify(z): 59 - z_3d = torch.stack([z, z, z]) 60 - z_norm = z_3d.clamp(0, 1) 61 - z_np = z_norm.detach().cpu().permute(1, 2, 0).numpy() 62 - z_bytes = (z_np * 255).round().astype("uint8") 63 - return Image.fromarray(z_bytes) 67 + _z = torch.clone(z).clamp_(0,1).mul_(255).round() 68 + z_np = _z.unsqueeze(2).expand(-1, -1, 3).type(torch.uint8).cpu().numpy() 69 + return Image.fromarray(z_np) 70 + 71 + def msave_cpu(x, f): 72 + mpilify_cpu(x).save(f"out/{f}.png") 64 73 65 74 def msave(x, f): 66 75 mpilify(x).save(f"out/{f}.png") 76 + 77 + def msave_alt(x, f): 78 + with io.BytesIO() as buffer: 79 + mpilify(x).save(buffer, format="png") 80 + buffer.getvalue() 81 + #_z = torch.clone(x).clamp_(0,1).mul_(255).round() 82 + #z_np = _z.unsqueeze(2).expand(-1, -1, 3).type(torch.uint8) 83 + #sft_save({"":_z.type(torch.uint8)}, f"out/{f}.mono.sft") 84 + #torch.save(z_np, "out/{f}.pt") 67 85 68 86 # 3 channels 69 87 def pilify(z):