t = 0 · noise, averaged by Animated groups · reports · clockwork orbits
How to find a time-symmetric animation
The animation#
Three different things go into this film, and the page keeps them apart: a symmetry, which says how the picture repeats in space and time; an equation, which says how the chemicals change from one moment to the next; and a method, which finds a film that obeys both.
Its symmetry#
In orbifold notation the symmetry group is r33₁3₂. Each 3 is a kind of centre about which the picture can be turned by 120°: plain 3 is γ in the picture above, 3₁ is α and 3₂ is β. The subscript counts the thirds of a period that an anticlockwise turn about that centre costs. So turning the picture about γ changes nothing; about α it shows the film as it will be a third of a period later; about β, two thirds later. The prefix r says that sliding the picture by a third of a cell costs a third of a period as well.
Written out, with the two chemicals and each of the nine symmetries of the simulation box carrying its cost :
for every symmetry , every point , every instant .
Only three of the nine cost nothing: doing nothing, and the two turns about γ. Those are all a single frame shows. The other six relate a frame to the one a third or two thirds of a period later.
The correspondence catalogue lists this group under ³3³3¹3: the same orbifold, with each centre marked by how many different moments its turns reach (³3 for α and β, ¹3 for γ). Its number there, 227, is only its place in Xu and Wu's list of the 275 spacetime groups.
The equation#
One equation, the Brusselator: two chemicals, and , react and diffuse at the same rate.
with , , on a triangular mesh of 36 × 36 nodes in a periodic box of side 40.
Nothing in the equation knows about the symmetry. What has to be found: the film repeats with period , so a single frame and the number determine all of it; everything else comes from simulating forward. The search is for one frame, 2 × 36 × 36 = 2 592 numbers, and one period. Nobody chooses ; it comes out as 6.390159918584649.
Why simulating does not work#
The obvious approach is to start somewhere, simulate, and wait. It fails for two reasons.
- Most of the symmetry is invisible to a simulator. It can impose the three free symmetries at every step, but the other six relate a frame to a later frame, so no single frame can satisfy or violate them.
- The animation is unstable. Even started exactly on it, a simulation drifts away: a disturbance of the right shape grows by a factor of 1.16 every period, and the simulation ends with every point oscillating in unison.
So instead of simulating towards the answer, the method writes the requirement as an equation for the frame and the period and solves it by Newton's method, which never asks whether a solution is stable. Newton's method needs a good first guess, and most of the work goes into that guess.
The method in five steps#
- The rest state and how it oscillates → a first guess for the period, and how and swing together.
- A starting pattern from the Brusselator's slow envelope → a pattern with the right symmetry, grown from random noise.
- Turn it into a Brusselator frame → the first guess for step 4.
- Solve for one frame and one number → the exact frame and period, by Newton–Krylov.
- Make the film and check it → the published animation.
Step 1 · The rest state and how it oscillates
Where nothing varies in space, the chemicals can sit still at , , where production and consumption balance. Linearise the reaction there:
The positive real part means the rest state is unstable: any small disturbance starts to oscillate, and grows into a steady oscillation. (That happens once ; at we are just past it.) The imaginary part gives the first guess for the period, , within 1 % of the final answer. The eigenvector, , says how moves relative to in that oscillation; step 3 uses it.
Step 2 · A starting pattern from the Brusselator's slow envelope
Close to the onset of oscillation, every point of the Brusselator swings almost like a sine wave at the frequency of step 1. What varies across space and time is only how strongly each point swings, and in which phase. Put those two into one complex number per point, : the envelope of the oscillation. Near onset the Brusselator reduces to an equation for the envelope alone,
whose constants come from the Brusselator: because the two chemicals diffuse equally, and , close to the Brusselator's own value at . The job set and measured the box in envelope units as , with the distance past onset.
The envelope has one property the full Brusselator lacks: multiply a solution by a constant phase and you get another solution. So its simplest periodic solutions are rotating waves, : a fixed pattern whose phase turns steadily. For such a solution, waiting a fraction of the period just multiplies the whole field by , so the symmetry of the film becomes
for every symmetry : a condition on one frame.
It is linear, so any field can be made to satisfy it by averaging over the nine symmetries, . And because the envelope equation respects both the turns and the phase rotation, a field that satisfies the condition keeps satisfying it as it is simulated. The job did exactly that:
- Start from random complex noise (random seed 1) and apply .
- Simulate the envelope 50 time units at a time, applying again after each stretch (only to remove round-off), and test whether the field has become a rotating wave, that is, whether for a single number . The job allowed 600 time units.
- Polish: solve to round-off with Newton's method, where is the right-hand side of the envelope equation.
t = 0 · noise, averaged by
t = 2
t = 5
t = 8
t = 12
t = 50 · a rotating waveThe dark dots were predicted before any simulation. A turn about α leaves the point α where it is, so there the condition reads , which forces ; the same holds at β. They are the points α and β of the film at the top, where the chemicals never move.
By the envelope is a rotating wave to 1.9e−8; the finite time step keeps it from getting closer than 3.4e−9, short of the job's test of 1e−9, so the run goes the full 600 time units (12 000 steps) and one polishing step finishes at 1.5e−14. The envelope is an approximation of the Brusselator, good near onset: the seed needs the right symmetry and roughly the right shape, and step 4 does the rest.
The sign. The minus in assumes the phase turns forwards. The job did not work that out in advance; it tried first. That also settles into a rotating wave, but with its clock running backwards: ⅓ and ⅔ swap, so α and β trade places. Checked against the catalogue entry it fails, with an error of 1.73 against a limit of 2e−7; the minus sign passes at 1.4e−15.
Step 3 · Turn it into a Brusselator frame
The envelope pattern becomes a frame for the two chemicals through the eigenvector of step 1:
Taking the real part gives a snapshot of the oscillation at one instant; multiplying by makes lag the way the oscillation requires; the field is scaled to unit root-mean-square and then by the amplitude . (Had Newton failed from 0.25, the job would have tried 0.50; it did not need to.) The period guess is from step 1. This seed has the right symmetry, inherited from , but not the right shape or size: it misses the equation of step 4 by 6.9e−2.
Step 4 · Solve for one frame and one number
The equation. Take a candidate frame and period . Simulate the Brusselator for a third of a period. Then apply a symmetry that costs a third of a period, say an anticlockwise turn about α. If is the answer, you are back where you started:
Here means "simulate forward for time " (RK4, time step 0.02, no symmetry imposed), and moves every value to where sends it. A third of a period is enough: doing it three times gives the whole period, and the ⅔ relations follow. Two more ingredients make the problem square:
- The three free symmetries are conditions on one frame, so they are imposed on by averaging. That leaves 868 free numbers.
- One more equation, a phase condition. Every frame of the film solves , so the solver must be told which frame to return: the total change from the starting guess must be perpendicular to the direction in which the film moves there.
Newton–Krylov. Newton's method linearises at the current guess and solves the
resulting linear system for a correction. The matrix of that system has one column per unknown,
and each column would cost a simulation, so it is never built. A Krylov solver (LGMRES) needs
only the matrix times a vector, and that is one extra simulation:
. That is all "Newton–Krylov" means. The
job used SciPy's root(method='krylov'), with the period as so it stays
positive.
Newton stalls for 35 steps, then converges in 8
Root-mean-square residual of against Newton iteration, on a log scale. Hover over the chart for each iteration's values, or open the table below.
For 35 iterations almost nothing happens: the residual goes from 6.9e−2 to 6.5e−2 and the period wanders between 6.355 and 6.363. The guess is outside the region where Newton's method converges quickly, and the steps are small and cautious. Then it gets close, and 8 iterations take the residual to 5.5e−16; in the last few, the number of correct digits roughly doubles each step, the signature of Newton's method. The whole solve took 43 iterations and 462 simulations of a third of a period, about 52 seconds on an ordinary laptop. The period it lands on is 6.390159918584649.
All 43 iterations
| iteration | residual (rms) | period |
|---|---|---|
| 0 (seed) | 6.91e−2 | 6.355087901 |
| 1 | 6.90e−2 | 6.355376850 |
| 2 | 6.90e−2 | 6.355640164 |
| 3 | 6.89e−2 | 6.355908375 |
| 4 | 6.89e−2 | 6.356217922 |
| 5 | 6.88e−2 | 6.356646522 |
| 6 | 6.87e−2 | 6.357485507 |
| 7 | 6.87e−2 | 6.359399204 |
| 8 | 6.86e−2 | 6.358540913 |
| 9 | 6.86e−2 | 6.358765997 |
| 10 | 6.86e−2 | 6.358634143 |
| 11 | 6.86e−2 | 6.358760603 |
| 12 | 6.86e−2 | 6.358725697 |
| 13 | 6.97e−2 | 6.363100669 |
| 14 | 6.91e−2 | 6.355541294 |
| 15 | 6.91e−2 | 6.355867273 |
| 16 | 6.90e−2 | 6.356345367 |
| 17 | 6.89e−2 | 6.357412892 |
| 18 | 6.89e−2 | 6.358794076 |
| 19 | 6.89e−2 | 6.358048852 |
| 20 | 6.90e−2 | 6.356641794 |
| 21 | 6.89e−2 | 6.358732336 |
| 22 | 6.87e−2 | 6.356632251 |
| 23 | 6.87e−2 | 6.357124595 |
| 24 | 6.85e−2 | 6.358245639 |
| 25 | 6.85e−2 | 6.358917788 |
| 26 | 6.85e−2 | 6.359072885 |
| 27 | 6.85e−2 | 6.358629551 |
| 28 | 6.85e−2 | 6.359601405 |
| 29 | 6.84e−2 | 6.357315230 |
| 30 | 6.84e−2 | 6.359505330 |
| 31 | 6.84e−2 | 6.358589162 |
| 32 | 6.84e−2 | 6.359059941 |
| 33 | 6.84e−2 | 6.358875481 |
| 34 | 6.84e−2 | 6.359107067 |
| 35 | 6.53e−2 | 6.362924196 |
| 36 | 5.34e−2 | 6.362740916 |
| 37 | 2.16e−2 | 6.464592811 |
| 38 | 8.92e−3 | 6.388589295 |
| 39 | 1.10e−3 | 6.391058216 |
| 40 | 4.79e−5 | 6.390270795 |
| 41 | 5.66e−6 | 6.390149298 |
| 42 | 3.82e−11 | 6.390159919 |
| 43 | 5.48e−16 | 6.390159919 |
seed · from step 3
iteration 35 · end of the stall6.5e−2
iteration 365.3e−2
iteration 372.2e−2
iteration 391.1e−3
iteration 43 · solved5.5e−16
Notice what never comes up in this step: stability. holds for an unstable film just as well as for a stable one, which is exactly why this works where simulating did not.
Step 5 · Make the film and check it
- The film. Simulate the Brusselator for one period from the solved frame, with no symmetry imposed, and save the frames (96 in the job; the published file keeps 48).
- The symmetry, checked. All nine relations hold on the film to 4.4e−9, against a limit of 2e−7. The film was simulated with nothing imposed, so this checks the answer rather than assuming it.
- Visible motion. A solution can satisfy the equation and still look static. The audit asks that every symmetry that costs time move the picture visibly at every moment, by at least 5 % of its range; this one moves it by at least 34 %.
- An independent replay. Simulate again from the first frame at two time steps without any averaging; the result must match the film to 1e−5. It matches to 9.3e−10 at the halved step, and closes up after one period to 4.2e−9. The published single-precision file replays to 4.7e−8, the round-off of single precision.
- A finer mesh. Resample to 48 × 48 nodes and solve again: 2 Newton steps, and the period moves by 6.2e−6 of itself, so the 36-node answer is resolved.
The published file is the solved frame polished once more, 48 frames of one period, averaged
over the nine symmetries so that symmetric samples are identical, and stored in single
precision. Re-running all five steps for this page reproduces it exactly: the same
SHA-256 hash, e47c12f9099f…, and a maximum difference of 0.
Where the symmetry comes from#
Does the Brusselator make this symmetric pattern by itself, or does the mesh? Neither. The symmetry is put in on purpose, in two steps, and after that only checked.
| step | symmetry put in |
|---|---|
| 2 · envelope | all nine, as conditions on one frame, by averaging the noise at the start and the field every 50 time units |
| 3 · lift | nothing new: the seed inherits it |
| 4 · Newton | the three free symmetries, by averaging the frame; one symmetry that costs a third of a period is the equation itself; the other five follow from these four |
| 5 · film | nothing: the Brusselator runs freely, and the film is checked against all nine |
| export | all nine, averaged once more so that symmetric samples are identical in the stored file |
The averaging in step 2 is what makes the pattern. Run the same noise through the same envelope equation without it, and the symmetric part, 11 % of the noise at the start, is down to 3.5e−6 of the field by ; every point then oscillates in unison. The mesh does nothing beyond letting each symmetry carry mesh points onto mesh points, which is why its side, 36, is a multiple of 3.
Run it yourself#
The search ran on 7 September 2026 as one job of 204 in a batch, g227-bruss-a1b23-L40-s1:
53.75 seconds on a two-core cloud container, about $0.0023, no graphics processor. The script
code/original.py runs the same job on your machine,
one step at a time, with the repository's own functions, and records everything this page
quotes, the control of the last section included:
git clone https://github.com/yaroslavvb/animated-groups-fable
cd animated-groups-fable/docs/reports/clockwork-orbits/code
python3 original.py # ~2 minutes
python3 figures.py # the pictures
original.py needs NumPy and SciPy and writes its record into original-run/;
figures.py needs Pillow and redraws this page's picture panels from that record.
The functions it calls live in rdlab.py:
cgl_relative_equilibrium and cgl_polish (step 2),
seed_from_complex (step 3), rpo_polish (step 4) and audit
(step 5). The job itself is run_brusselator in
the batch driver, and the export is in
build_equation_atlas.py. The
code README explains what each output means.
| equation | Brusselator, , , equal diffusion 1 |
| mesh | triangular, 36 × 36 nodes, box side 40; RK4, time step at most 0.02 |
| symmetry | r33₁3₂ (³3³3¹3 in the catalogue, entry g227), nine operations on the box |
| step 2 | envelope: , , , box 30.98; noise with random seed 1; up to 600 time units; sign tried first, then |
| step 3 | amplitude 0.25 (0.50 as a fallback), |
| step 4 | Newton–Krylov, LGMRES with at most 40 inner steps, at most 60 Newton steps, tolerance 1e−11; accepted below 1e−8 |
| step 5 | 96 frames; the site's audit limits; re-solve at 48 × 48 |
Where to go next
- A magic theorem for clockwork animations — what the symbol forces before any solver starts: which points must stay dark, and how the phase must wind around them. The still points α and β are its first example.
- The published animation, full screen, and its monochrome twin; the r33₁3₂ film in the showcase; its entry in the correspondence catalogue.
- The making of this site — the timeline: who asked for what, when, and what it cost.
- Background reading: Y. Kuramoto, Chemical Oscillations, Waves, and Turbulence, Springer, 1984, for how an oscillating reaction such as the Brusselator reduces to an equation for its slow envelope; M. Golubitsky and I. Stewart, The Symmetry Perspective, Birkhäuser, 2002, for symmetries that cost time.