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:
Converting spread rate to travel time:
For example if cell size = 30m and spread rate = 2m/min, then fire takes to move to a cardinal neighbor, and to move diagonally.
For this model, used an event-based arrival-time model which:
- Ignites one cell at time zero
- Calculates when the fire could reach its neighbors
- Selects the cell with the earliest pending arrival
- Spreads outward from that cell
- 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 queuepriority_queue = []# Add the ignition eventheapq.heappush( priority_queue, (0.0, ignition_row, ignition_col))processed_cells = 0while 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