Math198 - Hypergraphics
Last Modified 12/15/10 by Anna Galusza
Snowflake: A Simulation in Three Dimensions
Abstract
The goal of this project was to model the growth of snowflakes in three-dimensional space.
It was programmed in Python with OpenGL. I used Jim Crowell's
Aszgard package for creating applications in Syzygy.
Design
Snowflakes are crystals that form from water vapor at temperatures below
freezing. Although the freezing temperature of water is 0 degrees Celsius, snow
crystals tend to form at lower temperatures since, in order to crystallize, the
water molecules need something to attach to. Often, these will be small dust
particles. This process is called nucleation.
Once nucleation has occured, other water molecules that come in contact with the
mass also attach themselves to it. The process by which this actually ocurrs is not
well known, even in a qualitative sense. It is suspected that a quasi-liquid layer
of disordered water molecules forms on the surface of the crystal and the thickness
of this layer (which is different on the prism facets and the basal facets) dictates the
rate of growth of the facets.
Due to water's bent shape, it forms a hexagonal lattice at the temperatures at which
snowflakes form (there are other phases of ice - currently XIV are known; however,
they are irrelevant to this project since they do not occur to a significant extent
in the temperatures in whch snowflakes form and, hence, we will deal exclusively with
Ice Ih). As pictured above, this hexagonal lattice causes basal facets and prism
facets to form. The growth rates of each set of facets is dependant on the humidity and
water saturation of the atmosphere, thus causing the aforementioned factors to
greatly influence the shape of the snowflake. Since snowcrystal growth is affected by
even the smallest changes in atmospheric conditions and these conditions can vary
greatly from the time of nucleation to when the snowflake hits the earth, very
intricate patterns can from.
Another very interesting feature of snowflakes is that they sometimes grow dendrites
and, what more, they tend to grow six dendrites (although twelve sometimes occur when
plates grow on either end of a column with a 30 degree twist). Since snowflake crystals
form hexagonal prisms, there are six verteces to which water molecules diffuse faster
than to the six sides. Hence, once the snowflake is large enough for this distance to
be significant, the six verteces grow faster than the rest of the perimeter, causing
dendrites to form. This process occurs again on the dendrites; when they get large
enough, they too grow dendrites. The picture above portrays this well. Since the enire
snowflake experiences roughly the same atmospheric conditions at any one time, the
snowflake is also symmetrical.
Creating the Program
Since I had never programmed in Python before, let alone programmed graphics, the
first thing that I did was go through Stan Blank's tutorial, "Python Programming
in OpenGL", .
Since I would be dealing with molecules, experimenting with bounce.py seemed like
a good idea and, indeed, that is the code upon which I built my project. The
initial experiments consisted of adding first another and then an arbitrary number
of additional particles. Then came the question of how they should interact; I
made rudimentary versions where the particles interacted with each other through
elastic and then inelastic collisions. The latter was incorporated into my final
project, though later greatly simplified in order to increase the speed with which
the molecules are rendered.
The particles initially bounced off of the walls; however, when I implemented
inelastic collisions, I encountered the problem of their getting caught on the
walls of the simulation. After struggling somewhat with this, Professor Francis
suggested I put the molecules on a torus. Needless to say, this completely solved
the problem.
Since the molecules were meant to model water in its gaseous state, orderly
bouncing balls didn't work particularly well. Thus, I defined the particles to
move randomly (well, as randomly as numpy.random() allows). The algorithm for one
molecule sticking to another was initially the same as the one that I had created
for inelastic collisions. However, calculating the final velocities of the new
strucutre was inefficient (the number of particles in the simulation is in the
hundreds - hundred thousands at times) and, what more, unnecessary. Since the
motion was random, simply having the newly attached particle adopt the larger
clump's pattern of motion was much more efficient.
When I first added a third dimesion to the project, the bounding box was the
program window its self. Hence, there was no visible boundary for depth; the
particles just disappeared into the back of the screen and reappeared before you.
This was not very clear visually so, on Professor Francis's recommendation, I
added a bounding box that would let the user view all of the molecules and make it
clearer that the particles are disappearing because they are on a torus.
Once the program was running well in three dimensions, I added controls to allow
rotation around the x, y, and z axes and zoom in and out. At present, the user can
also add additional molecules to the simulation as well as pause/restart (this was
left in from the original bounce.py) the simulation.
In order to make the formation of the individual snow crystal more visible, I added
a seed to the simulation. As a result, particles that collide with the snow crystal
that includes the seed attach themselves to the mass. All other collisions are
ignored. (There is not much worry about the particles moving through each other
since their motions are random; thus, consecutively moving many times in the
same direction highly unlikely.)
By inscribing a tetrahedron in each molecule I hoped to model the binding behavior
of water. The tetrahedron's vertices are stored in a matrix which describes the
points at which the given molecule can bind. Upon contact with a molecule that was
already part of the snowflake, the new molecule translates its self so that it is at
the binding site of the molecule that it attached to. Next, I hoped to apply a rotation
to the matrix that describes that molecule's inscribed tetrahedron so that the next
molecule would bind correctly. While the translation appears to have worked and seems
to cause the appearance of a tetrahedronal snowflake, applying the rotation
caused a bit of a mess where once all particles were attached to the snowflake, there
were disconnected molecules that were in synchronous motion with the snowflake, hence
indicating that they were part of it.
The good news is that in all of these models, the principle of diffusion appears to play
a role in the formation of the snowflakes. When bulges form, these areas grow quicker
than the rest of the perimeter. The following shows the formation of one such snowflake.
This is one where the aforementioned translation was applied and the code for the rotaion
was commented out due to its lack of correctness.
Instructions
Upon executing the program, the default state is "paused." Press "a" to start the
animation and watch as a snowflake forms, Using the controls listed below, the
animation can be paused/started, additional particles can be added, the user can
zoom in and out, and the snowflake can be rotated as it forms.
a - (action) starts the simulation
s - (stop) pauses the simulation
n - (new) adds a new particle
e - zooms in
w - zooms out
i & m - rotate around the x-axis
k & l - rotate around the y-axis
u & o - rotate around the z-axis
Possible Future Modifications
- Modify the code to form hexagonal prisms, which then grow dendrites.
- Extend the Particle class to create a Molecule class that would paint a bent molecule, more closely resembling water.
- Modify the Molecule class to contain a positively charged hydrogen and a negatively charged oxygen, where opposite charges of neighboring molecules would attract and like charges repel.
- Add wind.
- Make code more efficient.
Links