]> git.mcshandy.xyz Git - barrow_crawler/commitdiff
Huge cleanup to pull things out of main etc, small improvements, etc
authorRandy McShandy <randy@mcshandy.xyz>
Fri, 15 Dec 2023 02:29:02 +0000 (20:29 -0600)
committerRandy McShandy <randy@mcshandy.xyz>
Fri, 15 Dec 2023 02:29:02 +0000 (20:29 -0600)
main.c
structs.c [new file with mode: 0644]
structs.h
utils.c
utils.h [deleted file]

diff --git a/main.c b/main.c
index d232420fe9aea64a4537038ef984fe81f0f91968..6efd62d12503cd76f73f8a8819c4958d86e816e5 100755 (executable)
--- a/main.c
+++ b/main.c
-#include <stdint.h>
-#include <math.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <pthread.h>
-#include <unistd.h>
-#define STB_IMAGE_WRITE_IMPLEMENTATION
-#include "stb_image_write.h"
-
-#define GRID_X 512
-#define GRID_Y GRID_X
-
-#define SHADOW 0
-#if SHADOW
-#define printf(a,...)
-#endif
-
-typedef struct
-{
-       double v[3][3];
-
-} Mat3;
-
-typedef struct
-{
-       float a;
-       float b;
-} FVec2;
-
-typedef struct
-{
-       int max_iterations;
-       double diff_a;
-       double diff_b;
-       double feed;
-       double kill;
-       double delta_t;
-
-       char name[32];
-} RD_Opts;
-
-typedef struct
-{
-       RD_Opts opts;
-       FVec2** source;
-       FVec2** dest;
-       int start_x;
-       int start_y;
-       int width;
-       int height;
-
-       pthread_mutex_t*        mutex;
-       pthread_mutex_t         worker_mutex;
-       pthread_cond_t*         worker_cond;
-       pthread_cond_t*         boss_cond;
-       pthread_barrier_t* barrier;
-
-       int* waiting_workers;
-       int worker_count;
-       int iterations;
-       int max_iterations;
-       int worker_id;
-} worker_arg;
-
-FVec2 ** grid;
-FVec2 ** grid_prime;
-FVec2 ** grid_temp;
-int master_iteration_done;
-
-// Connectivity increases as time passes (iterations or time delta)?
-// Seems we like <1.0 time deltas and higher iterations
-// diff values influence tightness, delta between them shouldn't get wider than ~0.5 or narrower than ~0.4
-RD_Opts puffer =
-{
-       .max_iterations = 1e4,
-       .diff_a = 0.7f,
-       .diff_b = 0.3f,
-       .feed = 0.055f,
-       .kill = 0.062f,
-       .delta_t = 1.0f,
-
-       .name = "puffer"
-};
-
-RD_Opts worms =
-{
-       .max_iterations = 1e4,
-       .diff_a = 0.7f,
-       .diff_b = 0.3f,
-       .feed = 0.082,
-       .kill = 0.06f,
-       .delta_t = 0.6f,
-
-       .name = "worms"
-};
-
-RD_Opts meiosis =
-{
-       .max_iterations = 1e4,
-       .diff_a = 0.7f,
-       .diff_b = 0.3f,
-       .feed = 0.0367f,
-       .kill = 0.0649f,
-       .delta_t = 1.0f,
-
-       .name = "meiosis"
-};
-
-const Mat3 laplacian_kernel =
-{
-       // oh shit
-       // Sum of all members must balance to 0.0 (or outer members have to do 1.0)
-       // it looks like any modifications should be on the order of 0.01 or less
-       // upper value of 22 <> 23 seems to be a good point
-       .v = {
-               {0.05f, 0.20f, 0.05f},
-               {0.20f, -1.0f, 0.20f},
-               {0.05f, 0.20f, 0.05f}
-       }
-};
-
-float kernel_sum(Mat3 kernel, Mat3 source)
-{
-       float result = 0.0f;
-
-       // Convolve kernel at grid[x,y]
-       for (int ix = 0; ix < 3; ix++)
-       {
-               for (int iy = 0; iy < 3; iy++)
-               {
-                       result += (kernel.v[ix][iy] * source.v[ix][iy]);
-               }
-       }
-
-       return result;
-}
-
-float rd_a_prime(FVec2** source_grid, RD_Opts opts, int x, int y, Mat3 kernel, float A, float B)
-{
-       float a_prime = 1.0f;
-       int x_less = (x-1 < 0) ? x : x-1;
-       int y_less = (y-1 < 0) ? y : y-1;
-       int x_more = (x+1 == GRID_X) ? x : x+1;
-       int y_more = (y+1 == GRID_Y) ? y : y+1;
-       // Use species A in the convolution, b_prime will need B
-       // For now we won't iterate over edge rows and columns to avoid special case vomit
-       Mat3 source =
-       {
-               .v =
-               {
-                       {grid[x_less][y_less].a,  grid[x][y_less].a,    grid[x_more][y_less].a},
-                       {grid[x_less][y+0].a,                   grid[x][y+0].a,                 grid[x_more][y+0].a},
-                       {grid[x_less][y_more].a,  grid[x][y_more].a,    grid[x_more][y_more].a},
-               }
-       };
-
-       a_prime = A + (opts.diff_a*(kernel_sum(kernel, source)) - (A*B*B) + opts.feed*(1.0f-A)) * opts.delta_t;
-       return a_prime;
-}
-
-float rd_b_prime(FVec2** source_grid, RD_Opts opts, int x, int y, Mat3 kernel, float A, float B)
-{
-       float b_prime = 1.0f;
-       int x_less = (x-1 < 0) ? x : x-1;
-       int y_less = (y-1 < 0) ? y : y-1;
-       int x_more = (x+1 == GRID_X) ? x : x+1;
-       int y_more = (y+1 == GRID_Y) ? y : y+1;
-       // Use species A in the convolution, b_prime will need B
-       Mat3 source =
-       {
-               .v =
-               {
-                       {grid[x_less][y_less].b,  grid[x][y_less].b,    grid[x_more][y_less].b},
-                       {grid[x_less][y+0].b,                   grid[x][y+0].b,                 grid[x_more][y+0].b},
-                       {grid[x_less][y_more].b,  grid[x][y_more].b,    grid[x_more][y_more].b},
-               }
-       };
-
-       b_prime = B + (opts.diff_b*(kernel_sum(kernel, source)) + A*(B*B) - (opts.kill + opts.feed)*B) * opts.delta_t;
-       return b_prime;
-}
-
-void* iterator(void* _arg)
-{
-       worker_arg* warg = (worker_arg*)_arg;
-       RD_Opts opts = warg->opts;
-       int start_x = warg->start_x;
-       int start_y = warg->start_y;
-       int w = warg->width;
-       int h = warg->height;
-
-       for (warg->iterations = 0; warg->iterations < warg->max_iterations; warg->iterations++)
-       {
-               printf("worker %d: work unit %d/%d\n", warg->worker_id, warg->iterations, warg->max_iterations);
-               for (int x = start_x; x < w + start_x && x < GRID_X; x++)
-               {
-                       for (int y = start_y; y < h + start_y && y < GRID_Y; y++)
-                       {
-                               FVec2 each = grid[x][y];
-                               grid_prime[x][y].a = rd_a_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
-                               grid_prime[x][y].b = rd_b_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
-                       }
-               }
-
-               pthread_mutex_lock(warg->mutex);
-               if (++*warg->waiting_workers == warg->worker_count)
-               {
-                       grid_temp = grid;
-                       grid = grid_prime;
-                       grid_prime = grid_temp;
-                       *warg->waiting_workers = 0;
-                       printf("worker-boss %d: completing report\n", warg->worker_id);
-                       if ((warg->iterations % 100 == 0))
-                       {
-                               char buffer[GRID_X][GRID_Y];
-                               for (int x = 0; x < GRID_X; x++)
-                               {
-                                       for (int y = 0; y < GRID_Y; y++)
-                                       {
-                                               buffer[x][y] = (uint8_t)(255.0f * grid[x][y].a);
-                                       }
-                               }
-                               char name[64] = {0};
-                               sprintf(name, "img/%s/%d.png", opts.name, warg->iterations);
-                               stbi_write_png(name, GRID_X, GRID_Y, 1, buffer, GRID_X * sizeof(uint8_t));
-                       }
-               }
-               pthread_mutex_unlock(warg->mutex);
-
-               pthread_barrier_wait(warg->barrier);
-
-#if 0
-               // Last one done should wake up the boss thread
-               int last_worker = 0;
-               pthread_mutex_lock(warg->mutex);
-               if (++*warg->waiting_workers == warg->worker_count)
-               {
-                       last_worker = 1;
-               }
-               pthread_mutex_unlock(warg->mutex);
-
-               if (last_worker == 0)
-               {
-                       pthread_cond_wait(warg->worker_cond, &warg->worker_mutex);
-               }
-               else
-               {
-                       grid_temp = grid;
-                       grid = grid_prime;
-                       grid_prime = grid_temp;
-
-                       // segfault somewhere in here lmao
-                       if ((warg->iterations % 100 == 0))
-                       {
-                               char buffer[GRID_X][GRID_Y];
-                               for (int x = 0; x < GRID_X; x++)
-                               {
-                                       for (int y = 0; y < GRID_Y; y++)
-                                       {
-                                               buffer[x][y] = (uint8_t)(255.0f * grid[x][y].a);
-                                       }
-                               }
-                               char name[64] = {0};
-                               sprintf(name, "img/%s/%d.png", opts.name, warg->iterations);
-                               stbi_write_png(name, GRID_X, GRID_Y, 1, buffer, GRID_X * sizeof(uint8_t));
-                       }
-                       printf("worker-boss %d: completing report\n", warg->worker_id);
-
-                       *warg->waiting_workers = 0;
-                       pthread_cond_broadcast(warg->worker_cond);
-               }
-#endif
-       }
-
-       printf("worker %d: exiting\n", warg->worker_id);
-       return _arg;
-}
-
-void* iterator_old(void* _arg)
-{
-       worker_arg* warg = (worker_arg*)_arg;
-       RD_Opts opts = warg->opts;
-       int start_x = warg->start_x;
-       int start_y = warg->start_y;
-       int w = warg->width;
-       int h = warg->height;
-
-       for (int iterations = 0; iterations < warg->max_iterations; iterations++)
-       {
-               printf("worker %d: work unit %d/%d\n", warg->worker_id, iterations, warg->max_iterations);
-               for (int x = start_x; x < w + start_x; x++)
-               {
-                       for (int y = start_y; y < h + start_y; y++)
-                       {
-                               FVec2 each = grid[x][y];
-                               grid_prime[x][y].a = rd_a_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
-                               grid_prime[x][y].b = rd_b_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
-                       }
-               }
-
-               // Last one done should wake up the boss thread
-               pthread_mutex_lock(warg->mutex);
-               ++*warg->waiting_workers;
-               if (*warg->waiting_workers == warg->worker_count)
-               {
-                       printf("worker %d: waking up boss\n", warg->worker_id);
-                       pthread_cond_signal(warg->boss_cond);
-               }
-               pthread_mutex_unlock(warg->mutex);
-
-               pthread_cond_wait(warg->worker_cond, &warg->worker_mutex);
-
-       }
-
-       printf("worker %d: exiting\n", warg->worker_id);
-       return _arg;
-}
+#include "structs.h"
 
 int main(int argc, char** argv)
 {
-       char chars[6] = {' ', ' ', ' ', '+', '#', '@'};
-       const int max_chars = sizeof(chars) / sizeof(chars[0]) - 1;
-
-       grid = (FVec2**)malloc(GRID_X * sizeof(FVec2*));
-       for (int n = 0; n < GRID_X; n++)
-       {
-               grid[n] = (FVec2*)malloc(GRID_Y * sizeof(FVec2));
-       }
-
-       grid_prime = (FVec2**)malloc(GRID_X * sizeof(FVec2*));
-       for (int n = 0; n < GRID_X; n++)
-       {
-               grid_prime[n] = (FVec2*)malloc(GRID_Y * sizeof(FVec2));
-       }
-
-       srand(time(NULL));
-
-       RD_Opts opts = puffer;
-
-       for (int x = 0; x < GRID_X; x++)
-       {
-               for (int y = 0; y < GRID_Y; y++)
-               {
-                       grid[x][y].a = 1.0f;
-                       grid[x][y].b = 0.0f;
-               }
-       }
 
-       const int max_rand = sqrt(GRID_X);
-       for (int n = 0; n < max_rand; n++)
+       RD_Opts meiosis_2 =
        {
-               grid[rand() % GRID_X][rand() % GRID_Y].b = 1.0f;
-       }
+               .max_iterations = 1e4,
+               .diff_a = 0.8f,
+               .diff_b = 0.4f,
+               .feed = 0.0367f,
+               .kill = 0.0649f,
+               .delta_t = 1.0f,
 
-       int waiting_workers = 0;
-       worker_arg warg = {
-               opts, grid, grid_prime, 0, 0, (GRID_X), (GRID_Y), .worker_count = 8, .waiting_workers = &waiting_workers, .max_iterations = 1e4,
+               .name = "meiosis_2"
        };
-       pthread_t threads[warg.worker_count];
-       pthread_mutex_t mutex;
-       pthread_cond_t worker_cond;
-       pthread_cond_t boss_cond;
-       pthread_barrier_t barrier;
-
-       pthread_mutex_init(&mutex, NULL);
-       pthread_cond_init(&worker_cond, NULL);
-       pthread_cond_init(&boss_cond, NULL);
-       pthread_barrier_init(&barrier, NULL, warg.worker_count);
-
-       warg.worker_cond        = &worker_cond;
-       warg.boss_cond          = &boss_cond;
-       warg.mutex                              = &mutex;
-       warg.barrier                    = &barrier;
-
-       worker_arg wargs[warg.worker_count];
-
-       for (int t = 0; t < warg.worker_count; t++)
-       {
-               wargs[t]                                                = warg;
-               wargs[t].worker_id      = t;
-               wargs[t].width                  = (GRID_X/warg.worker_count) + ((t == warg.worker_count-1) ? 0 : 4);
-               wargs[t].start_x                = (wargs[t].width * t);
-               pthread_mutex_init(&wargs[t].worker_mutex, NULL);
-               printf("worker %d x_span %d, %d\n", t, wargs[t].start_x, wargs[t].width);
-               pthread_create(&threads[t], NULL, iterator, &wargs[t]);
-       }
-
-       int should_quit = 0;
-       while(!should_quit)
-       {
-               pthread_mutex_lock(warg.mutex);
-                       if (wargs[0].iterations == wargs[0].max_iterations-1)
-                               should_quit = 1;
-               pthread_mutex_unlock(warg.mutex);
-       }
-
-       printf("boss: exiting loop\n");
-       for (int t = 0; t < warg.worker_count; t++)
-       {
-               pthread_join(threads[t], NULL);
-       }
-
-       printf("Opts: {\nIterations: %d\nTime delta: %f\nDiffA: %f\nDiffB: %f\nFeed: %f\nKill: %f\n\n}\n", wargs[0].max_iterations, opts.delta_t, opts.diff_a, opts.diff_b, opts.feed, opts.kill);
 
-       // It's end of execution, who cares
-       free(grid);
-       free(grid_prime);
+       generate_rd(4, puffer);
 
        return 0;
 }
diff --git a/structs.c b/structs.c
new file mode 100644 (file)
index 0000000..fa2591f
--- /dev/null
+++ b/structs.c
@@ -0,0 +1,57 @@
+#include "structs.h"
+
+// Connectivity increases as time passes (iterations or time delta)?
+// Seems we like <1.0 time deltas and higher iterations
+// diff values influence tightness, delta between them shouldn't get wider than ~0.5 or narrower than ~0.4
+RD_Opts puffer =
+{
+       .max_iterations = 1e4,
+       .diff_a = 0.8f,
+       .diff_b = 0.3f,
+       .feed = 0.055f,
+       .kill = 0.062f,
+       .delta_t = 0.6f,
+
+       .name = "puffer"
+};
+
+RD_Opts worms =
+{
+       .max_iterations = 1e4,
+       .diff_a = 0.7f,
+       .diff_b = 0.3f,
+       .feed = 0.082,
+       .kill = 0.06f,
+       .delta_t = 0.6f,
+
+       .name = "worms"
+};
+
+RD_Opts meiosis =
+{
+       .max_iterations = 1e4,
+       .diff_a = 0.7f,
+       .diff_b = 0.3f,
+       .feed = 0.0367f,
+       .kill = 0.0649f,
+       .delta_t = 1.0f,
+
+       .name = "meiosis"
+};
+
+const Mat3 laplacian_kernel =
+{
+       // oh shit
+       // Sum of all members must balance to 0.0 (or outer members have to do 1.0)
+       // it looks like any modifications should be on the order of 0.01 or less
+       // upper value of 22 <> 23 seems to be a good point
+       .v = {
+               {0.05f, 0.20f, 0.05f},
+               {0.20f, -1.0f, 0.20f},
+               {0.05f, 0.20f, 0.05f}
+       }
+};
+
+const char chars[6] = {' ', ' ', ' ', '+', '#', '@'};
+const int max_chars = sizeof(chars) / sizeof(chars[0]) - 1;
+
index c10ed09c66043e2ad15910ecdbc05ad30ea1ca27..50153bb6e332fbecf199b0519846be8f512b6548 100644 (file)
--- a/structs.h
+++ b/structs.h
@@ -1,24 +1,56 @@
-#define GRID_X 256
-#define GRID_Y 256
+#ifndef __RD_STRUCTS__
+#define __RD_STRUCTS__
+
+#include <pthread.h>
+
+#define GRID_X 128
+#define GRID_Y GRID_X
 
 typedef struct
 {
-    float v[3][3];
+       double v[3][3];
 
 } Mat3;
 
 typedef struct
 {
-    float a;
-    float b;
+       float a;
+       float b;
 } FVec2;
 
 typedef struct
 {
-    float diff_a;
-    float diff_b;
-    float feed;
-    float kill;
-    float delta_t;
+       int max_iterations;
+       double diff_a;
+       double diff_b;
+       double feed;
+       double kill;
+       double delta_t;
+
+       char name[32];
 } RD_Opts;
 
+typedef struct
+{
+       RD_Opts opts;
+       FVec2** source;
+       FVec2** dest;
+       int start_x;
+       int start_y;
+       int width;
+       int height;
+
+       int worker_count;
+       int iterations;
+       int max_iterations;
+       int worker_id;
+} worker_arg;
+
+extern RD_Opts puffer;
+extern RD_Opts worms;
+extern RD_Opts meiosis;
+extern const Mat3 laplacian_kernel;
+
+int generate_rd(int worker_count, RD_Opts opts);
+#endif //__RD_STRUCTS__
+
diff --git a/utils.c b/utils.c
index b20db7696a2df26bf90af2ef012abc3a890c60fa..28664a11c9da827034b3b1c828efe25e8b1bdb89 100644 (file)
--- a/utils.c
+++ b/utils.c
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <math.h>
 #include "structs.h"
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include "stb_image_write.h"
 
-FVec2 grid[GRID_X][GRID_Y];
-FVec2 grid_prime[GRID_X][GRID_Y];
+#define SHADOW 0
+#if SHADOW
+#define printf(a,...)
+#endif
 
-float convolve(Mat3 kernel, Mat3 source)
-{
-    float result = 0.0f;
-
-    // Convolve kernel at grid[x,y]
-    for (int ix = 0; ix < 3; ix++)
-    {
-        for (int iy = 0; iy < 3; iy++)
-        {
-            result += (kernel.v[ix][iy] * source.v[ix][iy]);
-        }
+worker_arg warg;
+int waiting_workers = 0;
+int should_quit = 0;
+
+pthread_t* threads;
+pthread_mutex_t mutex;
+pthread_barrier_t barrier;
+
+FVec2 ** grid;
+FVec2 ** grid_prime;
+FVec2 ** grid_temp;
+
+float kernel_sum(Mat3 kernel, Mat3 source) {
+  float result = 0.0f;
+
+  // Convolve kernel at grid[x,y]
+  for (int ix = 0; ix < 3; ix++) {
+    for (int iy = 0; iy < 3; iy++) {
+      result += (kernel.v[ix][iy] * source.v[ix][iy]);
     }
+  }
+
+  return result;
+}
+
+float rd_a_prime(FVec2 **source_grid, RD_Opts opts, int x, int y, Mat3 kernel,
+                 float A, float B) {
+  float a_prime = 1.0f;
+  int x_less = (x - 1 < 0) ? x : x - 1;
+  int y_less = (y - 1 < 0) ? y : y - 1;
+  int x_more = (x + 1 == GRID_X) ? x : x + 1;
+  int y_more = (y + 1 == GRID_Y) ? y : y + 1;
+
+  // Use species A in the convolution, b_prime will need B
+  // For now we won't iterate over edge rows and columns to avoid special case
+  // vomit
+  Mat3 source = {
+      .v = {
+          {grid[x_less][y_less].a, grid[x][y_less].a, grid[x_more][y_less].a},
+          {grid[x_less][y + 0].a, grid[x][y + 0].a, grid[x_more][y + 0].a},
+          {grid[x_less][y_more].a, grid[x][y_more].a, grid[x_more][y_more].a},
+      }};
+
+  a_prime = A + (opts.diff_a * (kernel_sum(kernel, source)) - (A * B * B) +
+                 opts.feed * (1.0f - A)) *
+                    opts.delta_t;
+  return a_prime;
+}
+
+float rd_b_prime(FVec2** source_grid, RD_Opts opts, int x, int y, Mat3 kernel, float A, float B)
+{
+       float b_prime = 1.0f;
+       int x_less = (x-1 < 0) ? x : x-1;
+       int y_less = (y-1 < 0) ? y : y-1;
+       int x_more = (x+1 == GRID_X) ? x : x+1;
+       int y_more = (y+1 == GRID_Y) ? y : y+1;
+
+       // Use species A in the convolution, b_prime will need B
+       Mat3 source =
+       {
+               .v =
+               {
+                       {grid[x_less][y_less].b,  grid[x][y_less].b,    grid[x_more][y_less].b},
+                       {grid[x_less][y+0].b,                   grid[x][y+0].b,                 grid[x_more][y+0].b},
+                       {grid[x_less][y_more].b,  grid[x][y_more].b,    grid[x_more][y_more].b},
+               }
+       };
+
+       b_prime = B + (opts.diff_b*(kernel_sum(kernel, source)) + A*(B*B) - (opts.kill + opts.feed)*B) * opts.delta_t;
+       return b_prime;
+}
+
+void* iterator(void* _arg)
+{
+       worker_arg* warg = (worker_arg*)_arg;
+       RD_Opts opts = warg->opts;
+       int start_x = warg->start_x;
+       int start_y = warg->start_y;
+       int w = warg->width;
+       int h = warg->height;
+
+       for (warg->iterations = 0; warg->iterations < warg->max_iterations; warg->iterations++)
+       {
+               printf("worker %d: work unit %d/%d\n", warg->worker_id, warg->iterations, warg->max_iterations);
+               for (int x = start_x; x < w + start_x && x < GRID_X; x++)
+               {
+                       for (int y = start_y; y < h + start_y && y < GRID_Y; y++)
+                       {
+                               FVec2 each = grid[x][y];
+                               grid_prime[x][y].a = rd_a_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
+                               grid_prime[x][y].b = rd_b_prime(grid, opts, x, y, laplacian_kernel, each.a, each.b);
+                       }
+               }
 
-    return result;
+               pthread_mutex_lock(&mutex);
+               if (++waiting_workers == warg->worker_count)
+               {
+                       grid_temp = grid;
+                       grid = grid_prime;
+                       grid_prime = grid_temp;
+                       waiting_workers = 0;
+                       printf("worker-boss %d: completing report\n", warg->worker_id);
+                       if ((warg->iterations % 100 == 0))
+                       {
+                               char buffer[GRID_X][GRID_Y];
+                               for (int x = 0; x < GRID_X; x++)
+                               {
+                                       for (int y = 0; y < GRID_Y; y++)
+                                       {
+                                               buffer[x][y] = (uint8_t)(255.0f * grid[x][y].a);
+                                       }
+                               }
+                               char name[64] = {0};
+                               sprintf(name, "img/%s/%d.png", opts.name, warg->iterations);
+                               stbi_write_png(name, GRID_X, GRID_Y, 1, buffer, GRID_X * sizeof(uint8_t));
+                       }
+               }
+               pthread_mutex_unlock(&mutex);
+               pthread_barrier_wait(&barrier);
+
+       }
+
+       // One last synchronization so boss thread doesn't die early
+       pthread_barrier_wait(&barrier);
+       should_quit = 1;
+
+       printf("worker %d: exiting\n", warg->worker_id);
+       return _arg;
 }
 
-float rd_a_prime(RD_Opts opts, int x, int y, Mat3 kernel, float A, float B)
+int initialize(int worker_count, RD_Opts active_opt)
 {
-    float a_prime = 1.0f;
-    // Use species A in the convolution, b_prime will need B
-    // For now we won't iterate over edge rows and columns to avoid special case vomit
-    Mat3 source =
-    {
-        .v =
-        {
-            {grid[x-1][y-1].a,  grid[x][y-1].a, grid[x+1][y-1].a},
-            {grid[x-1][y+0].a,  grid[x][y+0].a, grid[x+1][y+0].a},
-            {grid[x-1][y+1].a,  grid[x][y+1].a, grid[x+1][y+1].a},
-        }
-    };
-
-    a_prime = A + (opts.diff_a*(convolve(kernel, source)) - (A*B*B) + opts.feed*(1.0f-A)) * opts.delta_t;
-
-    return a_prime;
+       grid = (FVec2**)malloc(GRID_X * sizeof(FVec2*));
+       for (int n = 0; n < GRID_X; n++)
+       {
+               grid[n] = (FVec2*)malloc(GRID_Y * sizeof(FVec2));
+       }
+
+       grid_prime = (FVec2**)malloc(GRID_X * sizeof(FVec2*));
+       for (int n = 0; n < GRID_X; n++)
+       {
+               grid_prime[n] = (FVec2*)malloc(GRID_Y * sizeof(FVec2));
+       }
+
+       srand(time(NULL));
+
+       for (int x = 0; x < GRID_X; x++)
+       {
+               for (int y = 0; y < GRID_Y; y++)
+               {
+                       grid[x][y].a = 1.0f;
+                       grid[x][y].b = 0.0f;
+               }
+       }
+
+       const int max_rand = sqrt(GRID_X);
+       for (int n = 0; n < max_rand; n++)
+       {
+               grid[rand() % GRID_X][rand() % GRID_Y].b = 1.0f;
+       }
+
+       warg = (worker_arg){
+               active_opt, grid, grid_prime,
+               0, 0, (GRID_X), (GRID_Y),
+               .worker_count = worker_count,
+               .max_iterations = active_opt.max_iterations
+       };
+
+       threads = (pthread_t*)malloc(sizeof(pthread_t) * worker_count);
+       pthread_mutex_init(&mutex, NULL);
+       pthread_barrier_init(&barrier, NULL, warg.worker_count);
+
+       worker_arg wargs[worker_count];
+
+       for (int t = 0; t < warg.worker_count; t++)
+       {
+               wargs[t]                                                = warg;
+               wargs[t].worker_id      = t;
+               wargs[t].width                  = (GRID_X/worker_count) + ((t == worker_count-1) ? 0 : 4);
+               wargs[t].start_x                = (wargs[t].width * t);
+               printf("worker %d x_span %d, %d\n", t, wargs[t].start_x, wargs[t].width);
+               pthread_create(&threads[t], NULL, iterator, &wargs[t]);
+       }
+       return 0;
 }
 
-float rd_b_prime(RD_Opts opts, int x, int y, Mat3 kernel, float A, float B)
+int cleanup()
 {
-    float b_prime = 1.0f;
-    // Use species A in the convolution, b_prime will need B
-    Mat3 source =
-    {
-        .v =
-        {
-            {grid[x-1][y-1].b,  grid[x][y-1].b, grid[x+1][y-1].b},
-            {grid[x-1][y+0].b,  grid[x][y+0].b, grid[x+1][y+0].b},
-            {grid[x-1][y+1].b,  grid[x][y+1].b, grid[x+1][y+1].b},
-        }
-    };
-
-    b_prime = B + (opts.diff_b*(convolve(kernel, source)) + A*(B*B) - (opts.kill + opts.feed)*B) * opts.delta_t;
-
-    return b_prime;
+       printf("boss: exiting loop\n");
+       for (int t = 0; t < warg.worker_count; t++)
+       {
+               pthread_join(threads[t], NULL);
+       }
+
+       free(grid);
+       free(grid_prime);
+       free(threads);
+
+       return 0;
+}
+
+int generate_rd(int worker_count, RD_Opts active_opt)
+{
+       initialize(worker_count, active_opt);
+
+       // Would be smart to set up a semaphore and move per-workload processing here
+       while(!should_quit) {}
+
+       printf("Opts: {\nIterations: %d\nTime delta: %f\nDiffA: %f\nDiffB: %f\nFeed: %f\nKill: %f\n\n}\n", active_opt.max_iterations, active_opt.delta_t, active_opt.diff_a, active_opt.diff_b, active_opt.feed, active_opt.kill);
+
+       cleanup();
+       return 0;
 }
 
diff --git a/utils.h b/utils.h
deleted file mode 100644 (file)
index 8121a81..0000000
--- a/utils.h
+++ /dev/null
@@ -1,8 +0,0 @@
-
-float convolve(Mat3 kernel, Mat3 source);
-float rd_a_prime(RD_Opts opts, int x, int y, Mat3 kernel, float A, float B);
-float rd_b_prime(RD_Opts opts, int x, int y, Mat3 kernel, float A, float B);
-
-extern FVec2 grid[GRID_X][GRID_Y];
-extern FVec2 grid_prime[GRID_X][GRID_Y];
-