The population dynamics simulation known as Wa-Tor was described in a previous post. When carried out on a grid with periodic boundary conditions, the Wa-Tor "universe" is topologically equivalent to a torus, as depicted below using the code provided here.
The code below also requires the torus.py
import from an earlier blog post defining a class for depicting 3D objects in SVG.
from wator import World, EMPTY, FISH, SHARK
from torus import Torus
import random
import numpy as np
# Save every SAVE_EVERYth chronon iteration.
SAVE_EVERY = 5
# Run the simulation for MAX_CHRONONS chronons (time intervals).
MAX_CHRONONS = 2000
# PRNG seed.
SEED = 15
random.seed(SEED)
# The major and minor radius of the torus.
c, a = 2.5, 1.5
# Image dimensions and scaling factors from torus units to image units.
width, height = 800, 600
scalex, scaley = 100, 100
# Tait-Bryan angles for intrinsic rotation of the figure.
alpha, beta, gamma = 90, 35, 235
# Camera position, C, and projection plane position, E (relative to C).
cx, cy, cz = 0, 6, 0
ex, ey, ez = 0, 3, 0
C, E = np.array((cx,cy,cz)), np.array((ex,ey,ez))
def preamble(fo):
"""The SVG preamble and styles."""
print('<?xml version="1.0" encoding="utf-8"?>\n'
'<svg xmlns="http://www.w3.org/2000/svg"\n' + ' '*5 +
'xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="{}" >'
.format(width, height), file=fo)
print("""
<defs>
<style type="text/css"><![CDATA[""", file=fo)
print('path {stroke-width: 1px; stroke: #000;}', file=fo)
print("""]]></style>
</defs>""", file=fo)
world_width = nphi = 100
world_height = ntheta = int(world_width * c/a)
def get_colour(i, u):
"""Get a colour for quad i from the colourmap."""
cm = {EMPTY: '#00008b', FISH: '#ff69b4', SHARK: '#ffd700'}
return cm[u[i]]
def draw_torus(itr, u):
"""Draw a torus on iteration itr of the diffusion with array u."""
torus = Torus(c, a, ntheta, nphi)
torus.setup_torus()
torus.rotate_xyz(alpha, beta, gamma)
torus.get_perspective_view(C, E)
torus.get_quads()
# Draw the torus as a SVG image and save.
with open('frames/wator-{:04d}.svg'.format(itr), 'w') as fo:
preamble(fo)
for i in torus.idy:
quad = torus.quads[i] * (scalex, scaley) + (width/2, height/2)
colour = get_colour(i, u.ravel())
print('<path d="M{},{} L{},{} L{},{} L{},{} Z" fill="{}"/>'.format(
*quad.ravel(), colour), file=fo)
print('</svg>', file=fo)
world = World(world_width, world_height)
world.populate_world()
for chronon in range(MAX_CHRONONS):
if not chronon % SAVE_EVERY:
print('{}/{}: {}'.format(chronon, MAX_CHRONONS, len(world.creatures)))
draw_torus(chronon, np.array(world.get_world_image_array()))
alpha += 1
beta += 1
world.evolve_world()
wator.py
, as provided in the earlier blog post. has been customized with the following settings to make this simulation:
initial_energies = {FISH: 15, SHARK: 5}
fertility_thresholds = {FISH: 3, SHARK: 6}
Comments
Comments are pre-moderated. Please be patient and your comment will appear soon.
There are currently no comments
New Comment