Math198 - Hypergraphics
Last Modified 12/15/10 by Anna Galusza

Snowflake: A Simulation in Three Dimensions


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.


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 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 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.


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