Page 1 of 1

Belousov-Zhabotinsky sun catcher

Posted: August 1st, 2023, 4:51 pm
by pcallahan
Generated in a Python script with a hexagonal neighborhood and 120° symmetry, die-cut in two colors of acetate, and embedded in clear resin.
20230801_113853.jpg
20230801_113853.jpg (504.78 KiB) Viewed 21792 times
I realized after making a similar one that I could get three colored bands by cutting filters for adjacent bands and using the combination as the third color. This makes it possible to cut the filters at a higher level of detail. This is an 86mm disk and would be quite fragile otherwise and hard to remove from the cutting mat without breaking it. I made a small mistake and left islands in the red filter. I will add bridges for them when I make another.
20230731_093949.jpg
20230731_093949.jpg (203.34 KiB) Viewed 21792 times
Here you can see them casting a colored shadow. It does that in resin as well, but with less clarity.
20230731_093721.jpg
20230731_093721.jpg (223.93 KiB) Viewed 21792 times

Re: Belousov-Zhabotinsky sun catcher

Posted: September 16th, 2025, 7:42 am
by otismo
Do you have .rle 's for any of your Patterns ?

They must look great as colorful C. A. 's ...

Thank You !

Re: Belousov-Zhabotinsky sun catcher

Posted: September 17th, 2025, 2:02 am
by pcallahan
otismo wrote: September 16th, 2025, 7:42 am Do you have .rle 's for any of your Patterns ?
I generated them with floating point calculations on a 2D array so they're inherently dense. The same code could generate a series of images to animate, I think, but I never tried. I'll see if I can find it and post it.

Re: Belousov-Zhabotinsky sun catcher

Posted: September 17th, 2025, 10:49 pm
by pcallahan
otismo wrote: September 16th, 2025, 7:42 am Do you have .rle 's for any of your Patterns ?
Here's what I was able come up with. First, the Python code, which is mostly taken from elsewhere (with acknowledgments).

Code: Select all

import math
import numpy as np
from scipy.ndimage import convolve
from sys import argv
from PIL import Image

# Simulation method modified from https://scipython.com/blog/simulating-the-belousov-zhabotinsky-reaction/

# Side length of base rhombus (stored as an nXn grid)
n = 200 if len(argv) < 2 else int(argv[1])
# Value for all Belousov-Zhabotinsky reaction coefficients. 
param = 1 if len(argv) < 3 else float(argv[2])
# Number of interations to run.
niter = 500 if len(argv) < 4 else int(argv[3])

# Reaction parameters.
alpha, beta, gamma = param, param, param

# Shape of hexagonal neighborhood out to radius 3.
FILTER_STR = '''
1111000
1111100
1111110
1111111
0111111
0011111
0001111
'''
FILTER_INT = [[int(c) for c in row] for row in FILTER_STR.split()]
FILTER = np.array(FILTER_INT)/sum(sum(row) for row in FILTER_INT)

def update(p,arr):
    """Update arr[p] to arr[q] by evolving in time."""

    # Count the average amount of each species in the neighborhood around each cell
    # by convolution with FILTER
    q = (p+1) % 2
    s = np.zeros((3, arr.shape[2], arr.shape[3]))
    for k in range(3):
        s[k] = convolve(arr[p,k], FILTER, mode='wrap')

    # Apply the reaction equations
    arr[q,0] = s[0] + s[0]*(alpha*s[1] - gamma*s[2])
    arr[q,1] = s[1] + s[1]*(beta*s[2] - alpha*s[0])
    arr[q,2] = s[2] + s[2]*(gamma*s[0] - beta*s[1])

    # Ensure the species concentrations are kept within [0,1].
    np.clip(arr[q], 0, 1, arr[q])
    return arr

def equivalence(i, j, n):
  """Find the equivalent coordinates in the base rhombus by rotating through symmetries."""
  rot = 0
  while True:
    if ((i // n) + (j //n)) % 3 == 0:
      return i % n, j % n 
    i, j = -j - 1, i - j
    rot += 1

# Initialize the base rhombus with random amounts of A, B and C.
data = np.random.random(size=(2, 3, n, n))

# Build a 3nX3n patch based on 120-degree rhombic packing.
# This can be tiled with simple toroidal wrapping at the boundaries.
arr = np.zeros((2, 3, n * 3, n * 3))
for i in range(arr.shape[2]):
  for j in range(arr.shape[2]):
    ti, tj = equivalence(i, j, n)
    arr[:, :, i, j] = data[:, :, ti, tj]

# run the iteration
for i in range(0, niter):
  arr = update(i % 2, arr)

# Create an image from just the top nXn square, equivalent to the base rhombus
disp = np.concatenate((arr[(i + 1) % 2].transpose(2, 1, 0)[:n, :n, :], np.full((n, n, 1), 1, dtype=np.uint8)), axis=2)
img = Image.fromarray((disp * 255).astype(np.uint8), mode='RGBA')
w, h = img.size
img = img.transform((int(w * 3), int(h * math.sqrt(3))),
                    Image.Transform.AFFINE, (0.5, 0.5 / math.sqrt(3), -0.5 * w, 0, 1 / math.sqrt(3), 0),
                    resample=Image.Resampling.BICUBIC) 
img.save('/Users/calla/Downloads/zb3a.png')
img.show()
You can see how I modified it for a hex neighborhood to get the symmetry I wanted. This is an image I generated with it. It's a rhombus with periodic conditions when rotated.
zb3a.png
zb3a.png (218.31 KiB) Viewed 1924 times
I went into GIMP to fit three of these together with 120 degree rotations. I wasn't too careful about lining up the boundaries. I think I have code that does this part automatically anyway.
hex.PNG
hex.PNG (627.63 KiB) Viewed 1924 times
That's a hex tile that can be repeated without rotation and will cover the plane with a continuous Belousov-Zhabotinsky pattern. You could use it as wallpaper. Too bad the 60s are over because it might be in demand as a psychedelic backdrop.

You can generate a series of images like this to animate and I believe it will show the reaction dynamically. I was only interested in an image to use as a suncatcher so I never tried that.

Re: Belousov-Zhabotinsky sun catcher

Posted: June 14th, 2026, 12:44 am
by pcallahan
This is not a suncatcher yet. Here is a 6cm 3D-print of a symmetric Belousov-Zhabotinsky pattern. It captures the intensity as a height map but does not vary in color.
20260613_165508.jpg
20260613_165508.jpg (891.37 KiB) Viewed 608 times
I could print one or maybe something larger, mold it and cast it in resin (maybe smoothed out or maybe with the ridges to see what the optical effect is like). With a little work I could probably figure out a way to mask out the three colors. I am not sure I am that ambitious.

Here is the intensity map it's based on
zbcoaster.png
zbcoaster.png (192.3 KiB) Viewed 608 times
The code hasn't changed much and you can use GIMP or similar to separate and recombine the colors.

Re: Belousov-Zhabotinsky sun catcher

Posted: June 15th, 2026, 12:30 am
by pcallahan
Printable for anyone interested: https://www.printables.com/model/175446 ... ative-disk

I have plans to make this more general using tiles and other runs of the pattern.

Re: Belousov-Zhabotinsky sun catcher

Posted: June 22nd, 2026, 11:08 am
by pcallahan
I'm still working on this, but I can now set boundary conditions for 60-120 rhombus that tile both rotated and flipped. The continuity is sometimes a little off but on the whole the effect is believable. I will make some 3d-printed snap tiles when I get a chance.
image1-0.jpg
image1-0.jpg (2.07 MiB) Viewed 460 times
image1.jpg
image1.jpg (1.2 MiB) Viewed 460 times

Re: Belousov-Zhabotinsky sun catcher

Posted: June 26th, 2026, 1:23 pm
by pcallahan
Seamless Belousov-Zhabotinsky rhombus tiles. They tile both rotated and flipped and the boundary conditions were tricky to get right. Still a work in progress but moving along. The continuity on boundaries could be better and there might be way. I've also learned a little about how these oscillations actually work over time (nothing new I'm sure) and might post something in a real CA thread if I have any interesting observations. One thing worth doing other than physical tiles is making a looping animation.
20260626_093405.jpg
20260626_093405.jpg (1.37 MiB) Viewed 313 times
20260626_093619.jpg
20260626_093619.jpg (2.42 MiB) Viewed 313 times
20260626_095553.jpg
20260626_095553.jpg (1.74 MiB) Viewed 313 times

Re: Belousov-Zhabotinsky sun catcher

Posted: July 1st, 2026, 9:50 am
by pcallahan
Resin cast of symmetric periodic hexagon.
20260701_063606.jpg
20260701_063606.jpg (2.87 MiB) Viewed 225 times
PLA original embedded as a coaster.
20260701_062453.jpg
20260701_062453.jpg (983.94 KiB) Viewed 225 times

Re: Belousov-Zhabotinsky sun catcher

Posted: July 8th, 2026, 11:35 pm
by Ofas1998
pcallahan wrote: August 1st, 2023, 4:51 pm Generated in a Python script with a hexagonal neighborhood and 120° symmetry, die-cut in two colors of acetate, and embedded in clear resin. 20230801_113853.jpg I realized after making a similar one that I could get three colored bands by cutting filters for adjacent bands and using the combination as the third color. This makes it possible to cut the filters at a higher level of detail. This is an 86mm disk and would be quite fragile otherwise and hard to remove from the cutting mat without breaking it. I made a small mistake and left islands in the red filter. I will add bridges for them when I make another. 20230731_093949.jpg Here you can see them casting a colored shadow. It does that in resin as well, but with less clarity. 20230731_093721.jpg
:D :D :D

Re: Belousov-Zhabotinsky sun catcher

Posted: July 13th, 2026, 1:53 pm
by pcallahan
This won't be catching any sun but it's a different aesthetic. It is cast in AC730, a stone-like material, and I painted the grooves for contrast. Maybe I should make some cellular automata patterns like this. Either single generations of CGOL or rows of Rule 110.
20260711_172106.jpg
20260711_172106.jpg (3.29 MiB) Viewed 186 times