Final Project – Wildfire

Concept:

In order to define fire suppression tactics and design fire risk management policies, it is important to simulate the propagation of wildfires. In my final project, I’ll be using cellular automata to model the spread of wind-driven fire across a grid-based terrain, demonstrating the dynamics of wildfires and exploring different scenarios and factors affecting their spread.

Users will be able to set the initial conditions (i.e. density of vegetation, vegetation type, ignition point), adjust parameters (i.e. wind speed, wind direction, temperature), monitor variables (i.e. frames per second, land proportion, water proportion, burned land), pause, and reset the simulation.

Final Sketch:

https://editor.p5js.org/bdr/full/2S_n0X2gV

Code:

https://editor.p5js.org/bdr/sketches/2S_n0X2gV

Initial sketches:

View post on imgur.com

View post on imgur.com

Papers to be used:

https://www.fs.usda.gov/rm/pubs_int/int_rp115.pdf

Code walkthrough:
Terrain generation:

The generateCells() function creates a terrain by dividing the map into cells to form a 2D grid (representing a cellular automata). Within each grid cell (defined by x and y coordinates), various noise functions are used to generate different aspects of the terrain.

generateCells() mainly defines the elevation of each cell in the grid through a combination of noise functions. Noise, Marks, Distortion, Bump, and Roughness are all variables employed with different scaling factors and combinations of input derived from the x and y coordinates. The noise functions were determined through trial and error.

roughness = noise(x / 600, y / 600) - 0.3;
bumpdistort = noise(x / 20, y / 20);
bumpnoise = noise(x / 50, y / 50, 2 * bumpdistort);
h = noise1 + sq(sq(noise2)) + roughness * bumpnoise - 0.8;

The color of each point is determined based on its height and other noise values, influencing factors such as land type (e.g., vegetation or ocean) and terrain features.

Using HSB as the color mode, the hue component represents the color’s tone (e.g., red, green, blue) while the brightness component corresponds to the perceived elevation. This makes it intuitive to represent different elevations using a gradient of colors (e.g., blue for lower elevations to white for higher ones), making the terrain visually more coherent and natural-looking.

if (h > 0) {
  clr = color(20 + 10 * (marks1 - 4) + 10 * (marks2 - 4) + 20 * distort1 + 50 * distort2 + bumpnoise * 15,
  min(100, max(50, 100 - 500 * roughness)), 75 + 65 * h);
  veg = getColor(clr)
  pointData = { x: x, y: y, color: clr, vegetation: veg, fire: 0, elev: elevationClr, temp:null};
  landCnt++;

} else {
  clr = color(160, 100, 185 + max(-45, h * 500) + 65 * h + 75 * (noise2 - 0.75));
  veg = getColor(clr)
  pointData = { x: x, y: y, color: clr, vegetation: veg, fire: 0, elev: elevationClr, temp:null};
  oceanCnt++;
}

The elevation/height is mapped as to the more the cell is in the middle of the ocean, the deeper it gets, and the more in the middle of the land, the higher it gets.

Initial step:

View post on imgur.com

Simplified sketch: As the sketch needed around 3 seconds to render, and cellular automata required a constant update of the sketch, simplifying the sketch was crucial. So, instead of calculating the noise for every pixel, I skip one by predicting its color.

View post on imgur.com

Vegetation:

Vegetation type propagation probability:
– No vegetation: -1
– Cultivated: -0.4
– Forests: 0.4
– Shrub: 0.4

Vegetation density propagation probability:
– No vegetation: -1
– Sparse: -0.3
– Normal: 0
– Dense: 0.3

Rules:

R1: A cell that can’t be burned stays the same
R2: A cell that is burning down at the present time will be completely burned in the next iteration.
R3: A burned cell can’t be burned again.
R4: If a cell is burned, and its neighbors contain vegetation fue, the fire can then propagate with a given probability (factors).

The fire propagation probabilities are:

View post on imgur.com

P0: ignition point (user interaction)
P_veg: vegetation type
P_den: vegetation density
Ps: topography
Pw: wind speed and direction

View post on imgur.com

with C1 and C2 are adjustable coefficients
V is the wind speed
O is the angle between the wind direction and the fire propagation (if aligned, Pw increases)

View post on imgur.com

with a: adjustable coefficient
o: the slope angle of the terrain

View post on imgur.com

with E: elevation of the cell
D: the size of the square cell if adjacent or sqrt(2*cellSize) if diagonal

Cellular Automata rules:

Implement rules governing the spread of fire: Fuel, topography, wind, and humidity.
R1: A cell that can’t be burned stays the same
R2: A cell that is burning down at the present time will be completely burned in the next iteration.
R3: A burned cell can’t be burned again.
R4: If a cell is burned, and its neighbors contain vegetation fue, the fire can then propagate with a given probability (factors).

function generateNextGeneration() {
    for (let i = 0; i < width; i+=2) {
        for (let j = 0; j < height; j+=2) {
            let neighbors = countNeighbors(i, j);
            let windAffectedProb = calculateWindEffect(i, j, windSpeed, windDirection);

            if (grid[i][j].fire==0 && neighbors==0){ // no fire, neighbors no fire
                nextGrid[i][j].fire=0;
            }
            if (grid[i][j].fire==0 && neighbors!=0 && grid[i][j].vegetation==0){ // water, neighbor fire, probability 0%
                nextGrid[i][j].fire=0;
            }
            probability = Math.floor(random(1,100));
            windInfluence = random(0, 100);
            if (grid[i][j].fire==0 && neighbors!=0 && grid[i][j].vegetation==1 && probability<10 && windInfluence < windAffectedProb && temperature>0){ // sparse, neighbor fire, probability 10%
                nextGrid[i][j].fire=1;
                nextGrid[i][j].color=color(14, 252, 113);
            }
            probability = Math.floor(random(1,100));
            windInfluence = random(0, 100);
            if (grid[i][j].fire==0 && neighbors!=0 && grid[i][j].vegetation==2 && probability<50 && windInfluence < windAffectedProb && temperature>0){ // no fire, neighbor fire, normal veg, probability 70%
                nextGrid[i][j].fire=1;
                nextGrid[i][j].color=color(14, 252, 113);
            }
            probability = Math.floor(random(1,100));
            windInfluence = random(0, 100);
            if (grid[i][j].fire==0 && neighbors!=0 && grid[i][j].vegetation==3 && probability<30 && windInfluence < windAffectedProb && temperature>0){ // no fire, neighbor fire, dense veg, probability 100%
                nextGrid[i][j].fire=1;
                nextGrid[i][j].color=color(14, 252, 113);
            }
            else if (grid[i][j].fire==1){ // burning
                nextGrid[i][j].fire==-1;
                nextGrid[i][j].color=color(0, 0, 57);
                burnedCnt++;
                burnedBlocks[`${i}_${j}`] = true;
            }
            else if (grid[i][j].fire==-1){ // burned
                nextGrid[i][j].fire==-1;
                nextGrid[i][j].color=color(0, 0, 57);
            }
        }
    }
    swapGenerations();
}
Other Maps:

Elevation Map: Users are able to visualize the elevation of the terrain by using the button at the right of the screen.

View post on imgur.com

 

Elevation type: Users are also able to visualize the tyoe of vegetation (forests, shrubs, cultivated…)

View post on imgur.com

Wind: Users are also able to see the wind direction and modify it using the slider.

View post on imgur.com

Challenges:

Improving the computation time was a rather challenging time. After optimizing it, it went from 3s to 0.35s.

IM Show Pictures:

View post on imgur.com

View post on imgur.com

 

Leave a Reply

Your email address will not be published. Required fields are marked *