Wednesday 19 August 2015

Simulating Rainfall


So not every post on here is going to be about the game 'Create'. Today I'm going to create a simulation that takes rainfall data and a height map and attempts to predict where the rain will end up, based on the height of the terrain, the intensity of the rainfall, and the direction the rain is moving.

I have a 72 megapixel height map of Great Britain, however as each pixel needs to be taken into account for the simulation, I'm going to scale that down to 18 megapixels or possibly smaller depending on the speed of the simulation.

I've also grabbed some rainfall data and photoshopped it into several frames, which can be used as the source of rain in the simulation, it's not at all realistic, but it should be interesting to see what happens :)

I will start by breaking up height map into individual cells (with one pixel corresponding to one cell). The cell with have the following properties:

  • Absorption potential (i.e. how much water that cell can hold before becoming saturated and surface water starts to accumulate)
  • Water level (how much water is actually in this cell)
  • Elevation (Each cell will attempt to pass water to cells at a same or lower elevation than itself) 
  • List of neighbouring cells
The cell will also require the following methods:
  • Add Rain (takes a value and adds it to the water level)
  • Distribute Rain (simulates the flow of water down hill)
  • Get Water Level (returns the value of the current water level)
  • Set/Get elevation
  • Set number of neighbours
  • Connect cell to neighbour
  • Get/Set absorption potential
Here is what that all looks like in code:

Next I will have to read in the height map, and create a new cell for each pixel. The algorithm is:

  • Open image
  • Iterate through each pixel
  • For each pixel, create a new cell with the X and Y coordinates of the pixel, and an elevation determined by the pixel colour.
  • If the pixel colour is black, set its absorption potential to zero, and its water level to 1000 (black pixels in the height map represent the sea, land is grey, higher land is white)
  • After creating all the cells, iterate over all the cells, connecting them with their neighbours
I created an image handler class which simply reads in each pixel of the height map, and returns a two dimensional array of the pixel values:



I also created a simulation class, with a method called 'createCells' which implements the above algorithm:



Now to actually start the simulation, I will create another method simply named 'startSimulation' in the Simulation class. The algorithm will be:

  • Start at iteration 1
  • If the iteration is less than or equal to 7, load the rainfall data image
  • Iterate over each pixel of the rainfall data
  • If the pixel is completely white, there is no rainfall, proceed to the next pixel
  • Add the rainfall amount to the corresponding cell
  • After adding all the rainfall data, iterate through each cell and call distributeRain()
  • Generate an image of the current water levels and output it
Here is the code:



It was interesting to observe that the water actually drains into valleys and follows the paths of rivers. The resulting image is a bit grainy, but that's partially due to the resolution of the topography data.


No comments:

Post a Comment