Skip to content

Python bindings to the Behave fire modelling framework

License

Notifications You must be signed in to change notification settings

j-tenny/pyrothermel

Repository files navigation

Pyrothermel

Model fire rate of spread, intensity, and more for surface fires and crown fires using the extended Rothermel model. Pyrothermel provides a Python interface to the C++ code that underlies Behave, Flammap, and other software tools maintained by the Missoula Fire Lab*.

Please submit bugs and feature requests as Github issues. Note, there may be some API changes in early versions of this package.

*Pyrothermel and its authors are not associated with the Missoula Fire Lab or the US Government.

Dependencies

  • Python >= 3.8
  • setuptools
  • A C++ compiler The C++ compilers used for testing were Visual Studio 2022 and gcc for WSL. A compiler is not needed if you are using Windows, Python version 12, and amd64 processor architecture.

Quick Install

pip install pyrothermel

Manual Install

Download

git clone https://github.com/j-tenny/pyrothermel.git

Build

python setup.py bdist_wheel

Install (Will need to replace filename of wheel to match your machine and python version)

pip install dist/[your-file-name.whl] --force-reinstall

Quickstart

import pyrothermel
import pandas as pd
import seaborn as sns

Setup Base Fuel Model and Moisture Scenario

moisture = pyrothermel.MoistureScenario.from_existing(dead_fuel_moisture_class='low',live_fuel_moisture_class='moderate')
fuel = pyrothermel.FuelModel.from_existing(identifier='TL8')
canopy_base_height = 2.5 # default unit is m
canopy_bulk_density = .1 # default unit is kg/m^3

# Print some fuel loading values from fuel model TL8
print([fuel.fuel_load_one_hour, fuel.fuel_load_ten_hour, fuel.fuel_load_hundred_hour])
print(fuel.units.loading_units)
[1.300187341185569, 0.31383832373444764, 0.2465872543627803]
LoadingUnitsEnum.KilogramsPerSquareMeter

Run Rothermel Models Across Range of Wind Speeds

results_list = []
for wind_speed in range(0,60,2):
    run = pyrothermel.PyrothermelRun(fuel,moisture,wind_speed,wind_input_mode='ten_meter',canopy_base_height=canopy_base_height,canopy_bulk_density=canopy_bulk_density,canopy_cover=.5,canopy_height=20,canopy_ratio=.6)
    results_surface = run.run_surface_fire_in_direction_of_max_spread()
    results_final = run.run_crown_fire_scott_and_reinhardt()
    results_final['wind_speed'] = wind_speed
    results_final['treatment'] = 'untreated'
    results_list.append(results_final)
    
untreated_crowning_index = run.calculate_crowning_index()
untreated_torching_index = run.calculate_torching_index()
    
df = pd.DataFrame(results_list)
df
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
spread_rate flame_length fireline_intensity scorch_height transition_ratio active_ratio fire_type wind_speed treatment
0 0.035297 0.850504 182.940784 5.005403 0.274758 0.025974 Surface 0 untreated
1 0.036477 0.863471 189.058483 5.150455 0.283946 0.033603 Surface 2 untreated
2 0.038485 0.885015 199.463628 5.391881 0.299574 0.046541 Surface 4 untreated
3 0.040997 0.911142 212.486479 5.685303 0.319133 0.062713 Surface 6 untreated
4 0.043907 0.940336 227.566123 6.013981 0.341781 0.081423 Surface 8 untreated
5 0.047152 0.971693 244.386618 6.367902 0.367044 0.102279 Surface 10 untreated
6 0.050693 1.004603 262.738585 6.740268 0.394606 0.125023 Surface 12 untreated
7 0.054500 1.038631 282.470446 7.126172 0.424242 0.149466 Surface 14 untreated
8 0.058551 1.073456 303.466091 7.521935 0.455775 0.175465 Surface 16 untreated
9 0.062828 1.108839 325.633015 7.924731 0.489067 0.202906 Surface 18 untreated
10 0.067316 1.144599 348.895334 8.332347 0.524005 0.231694 Surface 20 untreated
11 0.072003 1.180595 373.189391 8.743023 0.560492 0.261751 Surface 22 untreated
12 0.076879 1.216721 398.460819 9.155342 0.598447 0.293011 Surface 24 untreated
13 0.081935 1.252892 424.662512 9.568151 0.637799 0.325414 Surface 26 untreated
14 0.087161 1.289045 451.753155 9.980508 0.678487 0.358909 Surface 28 untreated
15 0.092553 1.325129 479.696141 10.391632 0.720454 0.393453 Surface 30 untreated
16 0.098102 1.361104 508.458756 10.800878 0.763653 0.429003 Surface 32 untreated
17 0.103804 1.396940 538.011536 11.207708 0.808038 0.465524 Surface 34 untreated
18 0.109653 1.432613 568.327776 11.611672 0.853570 0.502983 Surface 36 untreated
19 0.115645 1.468107 599.383126 12.012394 0.900212 0.541350 Surface 38 untreated
20 0.121775 1.503406 631.155270 12.409561 0.947930 0.580597 Surface 40 untreated
21 0.128040 1.538500 663.623663 12.802911 0.996695 0.620699 Surface 42 untreated
22 0.241603 3.448728 1474.064719 13.192226 1.046476 0.661632 Torching 44 untreated
23 0.379762 5.160256 2697.956066 13.577327 1.097248 0.703375 Torching 46 untreated
24 0.536191 7.103385 4357.386068 13.958064 1.148986 0.745907 Torching 48 untreated
25 0.711691 9.296938 6524.360652 14.334319 1.201667 0.789210 Torching 50 untreated
26 0.907056 11.754955 9275.974007 14.705996 1.255270 0.833266 Torching 52 untreated
27 1.123074 14.489637 12694.462206 15.073021 1.309773 0.878058 Torching 54 untreated
28 1.360525 17.512343 16867.255868 15.435336 1.365159 0.923571 Torching 56 untreated
29 1.620185 20.833995 21887.031854 15.792902 1.421409 0.969790 Torching 58 untreated

Modify Fuel Loading and Recalculate

fuel.fuel_load_one_hour *= .5
fuel.fuel_load_ten_hour *= .5
fuel.fuel_load_hundred_hour *= .75
fuel.fuel_bed_depth *= .5

results_list = []
for wind_speed in range(0,60,2):
    run = pyrothermel.PyrothermelRun(fuel,moisture,wind_speed,wind_input_mode='ten_meter',canopy_base_height=2.5,canopy_bulk_density=.1,canopy_cover=.5,canopy_height=20,canopy_ratio=.6)
    results_surface = run.run_surface_fire_in_direction_of_max_spread()
    results_final = run.run_crown_fire_scott_and_reinhardt()
    results_final['wind_speed'] = wind_speed
    results_final['treatment'] = 'treated'
    results_list.append(results_final)

treated_crowning_index = run.calculate_crowning_index()
treated_torching_index = run.calculate_torching_index()

df_treated = pd.DataFrame(results_list)
df = pd.concat([df,df_treated])

Display Results

sns.lineplot(df,x='wind_speed',y='flame_length',hue='treatment').set(xlabel='Wind Speed (km/hr)',ylabel='Flame Length (m)')
[Text(0.5, 0, 'Wind Speed (km/hr)'), Text(0, 0.5, 'Flame Length (m)')]

png

print('Wind Speed to initiate crown fire in untreated stand: ', untreated_torching_index, ' km/hr')
print('Wind Speed to initiate crown fire in treated stand: ', treated_torching_index, ' km/hr')
print('Wind Speed to propagate crown fire in untreated stand: ', untreated_crowning_index, ' km/hr')
print('Wind Speed to propagate crown fire in treated stand: ', treated_crowning_index, ' km/hr')
Wind Speed to initiate crown fire in untreated stand:  43  km/hr
Wind Speed to initiate crown fire in treated stand:  98  km/hr
Wind Speed to propagate crown fire in untreated stand:  60  km/hr
Wind Speed to propagate crown fire in treated stand:  60  km/hr

About

Python bindings to the Behave fire modelling framework

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published