First toy model

I’m learning about fire modeling, and trying to progress my Python abilities as well. So I thought I’d try to document the process. Starting at the beginning, I wanted to create a simple landscape fire spread model based on Minimum Travel Time (MTT). MTT is similar to the Shortest Path Problem, where each raster cell…

Written by

I’m learning about fire modeling, and trying to progress my Python abilities as well. So I thought I’d try to document the process.

Starting at the beginning, I wanted to create a simple landscape fire spread model based on Minimum Travel Time (MTT). MTT is similar to the Shortest Path Problem, where each raster cell is treated like a node on a network.

For the first model:

  • each raster cell is either unburned, burning, or burned
  • fire spreads only to neighboring cells
  • each cell has a spread rate or travel cost
  • the model records fire-arrival time at each cell

Defining the neighbors as the nearest 8-neighbor grid:

NW   N   NE
W x E
SW S SE

The cardinal neighbors are one cell-width away. Diagonal neighbors are d distance away: ddiagonal=2×cell sized_{diagonal} = \sqrt{2} \times \text{cell size}

Converting spread rate to travel time: travel time=distance between cell centersrate of spread\text{travel time} = \frac{\text{distance between cell centers}}{\text{rate of spread}}

For example if cell size = 30m and spread rate = 2m/min, then fire takes 30/2=15 minutes30 / 2 = 15 \text{ minutes} to move to a cardinal neighbor, and 302/2≈21.2 minutes30\sqrt{2}/2 \approx 21.2 \text{ minutes} to move diagonally.

For this model, used an event-based arrival-time model which:

  1. Ignites one cell at time zero
  2. Calculates when the fire could reach its neighbors
  3. Selects the cell with the earliest pending arrival
  4. Spreads outward from that cell
  5. Continues until no reachable cells remain or the simulation reaches a stopping time

I started out not knowing much of anything about coding. I took a Pascal class back in high school in the 90’s, and had such a rough time that I swore I would avoid coding after that. I realize that I need to have an open mind about learning some coding, especially Python, so I thought this project (learning about fire modeling in general) would be a good time to work on that. I used ChatGPT for much of the code here, always with an eye towards understanding what was happening within the code.

I started with a small synthetic landscape with 30m cells and a spread rate of 2.0 across the entire raster. The landscape was just a Numpy array with 25 rows and 25 columns, and I set the ignition cell as the center, (12,12).

ChatGPT’s recommendation for progressing the MTT model was using the heapq algorithm. Here is the code block of the actual queue model:

# Create an empty priority queue
priority_queue = []
# Add the ignition event
heapq.heappush(
priority_queue,
(0.0, ignition_row, ignition_col)
)
processed_cells = 0
while priority_queue:
# Remove the event with the earliest arrival time
current_time, current_row, current_col = heapq.heappop(
priority_queue
)
# Skip this event if a faster route to the cell was found later
if current_time > arrival_time[current_row, current_col]:
continue
processed_cells += 1
# Find all valid neighbors of the current cell
neighbors = get_valid_neighbors(
row=current_row,
col=current_col,
n_rows=n_rows,
n_cols=n_cols,
cell_size=cell_size,
)
# Use the spread rate of the current cell
current_rate = spread_rate[current_row, current_col]
for neighbor in neighbors:
neighbor_row = neighbor["row"]
neighbor_col = neighbor["col"]
distance = neighbor["distance"]
# Calculate travel time between the two cell centers
travel_time = distance / current_rate
# Add travel time to the current cell's arrival time
proposed_arrival_time = current_time + travel_time
# Keep the proposed route only if it is faster
if proposed_arrival_time < arrival_time[
neighbor_row,
neighbor_col
]:
arrival_time[
neighbor_row,
neighbor_col
] = proposed_arrival_time
# Add the improved arrival event to the queue
heapq.heappush(
priority_queue,
(
proposed_arrival_time,
neighbor_row,
neighbor_col,
)
)

Here is a graphical output of the simple model from the above code. It is basically a no-wind no-slope fire spread across a homogeneous landscape (every cell has the same spread rate). Fire spreads evenly out from the center ignition point.

Now that I had a simple spread model that worked I could add heterogeneous fuels. I added a patch of faster spread rate, a patch of slower spread rate, and a line of non-burnable pixels. Running the model on that fake landscape produces a markedly different set of arrival-time contours.

In this case fire behavior is so oversimplified because it is represented by a simple “spread rate” saved in each cell. It doesn’t take into account any of the actual contributors to fire spread (see Rothermel, 1972). But it was a good place to start looking at how to write some Python code and also how to think about a model.

Leave a comment