Traduction en cours
Hourly FWI Tutorial - Python
Last updated: February 27th, 2026
Python files
The following files can be found on the cffdrs-ng GitHub repository:
- data/
- FWI/
- Python/
If you are unfamiliar with GitHub, there are many options for you to retrieve the code and data files:
- Download each file to your computer individually. On the file's GitHub page (e.g. PRF2007_hourly_wx.csv), find the "More file actions" button at the top-right side of the website (denoted "..."), and select "Download". This will begin downloading based on your browser settings. Repeat this for every file.
- Download the whole repository to your computer. See the GitHub documentation for more information.
- Clone the whole repository to your computer with Git. See the GitHub documentation for more information.
- Fork the repository to create a new repository on GitHub. See the GitHub documentation for more information.
Besides the files, ensure you have the required Python packages, which are listed in the code documentation.
Data
PRF2007_hourly_wx.csv contains hourly weather recorded from a Petawawa Research Forest (PRF) weather station during the 2007 field season. The data has no gaps and is sorted sequentially by time, which is a requirement for FWI2025 input data.
The column headers are those required for hourly FWI calculations, details of which can be found in the code documentation. Grassland fuel load (grass_fuel_load), grassland curing (percent_cured) and solar radiation (solrad) are not included, but these are optional inputs and they will be automatically calculated if not provided. There is a column for UTC offset (timezone) which will be used by default in the hFWI() function.
Steps
Open the tutorial_hourly_FWI.py code file. You can either follow the code and comments in the file or continue on this page (both include the same code and content).
Load packages
Run pip install to install any you are missing.
import pandas as pd
import sys
Load functions and data
This tutorial will refer to file locations as structured in the GitHub repository. Specify the local path to the cffdrs-ng folder. It can accept absolute paths (e.g. starting with "C:/") or relative paths (e.g. "./" if the working directory is cffdrs-ng). Change the path strings to match your file layout if it is different.
path_prefix = "CHANGE/TO/PATH/TO/cffdrs-ng/"
sys.path.append(path_prefix + "FWI/Python")
Load the files containing the variables and functions to calculate FWI2025.
from NG_FWI import hFWI
from daily_summaries import generate_daily_summaries
Load the input weather station data file.
data = pd.read_csv(path_prefix + "data/PRF2007_hourly_wx.csv")
Print the column names, data should contain 12 columns.
print(data.columns)
Index(['id', 'lat', 'long', 'timezone', 'yr', 'mon', 'day', 'hr', 'temp', 'rh',
'ws', 'prec'],
dtype='object')
Run FWI2025
hFWI() is the function that calculates hourly FWI codes in FWI2025. Details about it can be found in the code documentation. It can handle multiple stations and years/fire seasons (not shown in this tutorial). For details you can run the help.
help(hFWI)
Help on function hFWI in module NG_FWI:
hFWI(
df_wx,
timezone=None,
ffmc_old=85.0,
mcffmc_old=None,
dmc_old=6.0,
dc_old=15.0,
mcgfmc_matted_old=16.3075131042516,
mcgfmc_standing_old=16.3075131042516,
prec_cumulative=0.0,
canopy_drying=0,
silent=False,
round_out=4
)
##
# Calculate hourly FWI indices from hourly weather stream.
#
# @param df_wx hourly values weather stream
...
For this tutorial, we will leave all the optional parameters to default.
data_fwi = hFWI(data)
########
FWI2025 (YYYY-MM-DD)
Startup values used:
FFMC = 85.0 % and mcffmc = None
DMC = 6.0 and DC = 15.0
mcgfmc matted = 16.3075 % and standing = 16.3075 %
cumulative precipitation = 0.0 mm and canopy drying = 0
Running PRF for 2007
########
Output is a DataFrame, with FWI calculations appended after the input columns. Save the output as a CSV file (overrides any preexisting file).
data_fwi.to_csv(path_prefix + "PRF2007_hourly_FWI.csv", index = False)
Print the last two rows of the standard moisture codes and fire behaviour indices.
standard_components = ['ffmc', 'dmc', 'dc', 'isi', 'bui', 'fwi']
print(data_fwi.loc[:, standard_components].tail(2))
ffmc dmc dc isi bui fwi
2621 80.2669 3.0924 219.5169 1.6423 5.9745 0.7650
2622 82.1759 3.3503 220.0533 2.1462 6.4550 1.2023
Print a simple summary of the standard FWI components.
print(data_fwi.loc[:, standard_components].describe())
ffmc dmc dc isi bui fwi
count 2623.000000 2623.000000 2623.000000 2623.000000 2623.000000 2623.000000
mean 70.622770 17.487231 136.122169 2.158163 23.971546 3.877128
std 22.973326 13.331302 76.454242 2.233486 17.499332 4.438263
min 0.000000 0.000000 15.409200 0.000000 0.000000 0.000000
25% 67.866500 5.924600 72.276400 0.787700 8.407750 0.422050
50% 79.377900 16.460900 133.062700 1.395800 22.623400 2.407500
75% 85.177050 26.511200 188.638500 2.978500 34.605350 5.929900
max 94.397300 50.174000 292.950100 17.595800 66.148100 25.135200
Compare your outputs with our standard outputs in PRF2007_standard_hourly_FWI.csv.
Calculate daily summaries
Calculate outputs like peak burn time and number of hours of spread potential. Details about the daily summaries function can be found in the FWI2025 - code documentation.
report = generate_daily_summaries(data_fwi)
########
FWI2025: Daily Summaries (YYYY-MM-DD)
Summarizing PRF to daily
########
Print a simple summary of the daily report.
daily_components = ["peak_hr", "duration", "isi_smooth", "dsr"]
print(report[daily_components].describe())
peak_hr duration isi_smooth dsr
count 109.000000 109.000000 109.000000 109.000000
mean 17.293578 2.697248 4.324269 1.553256
std 1.271502 3.818824 3.220367 1.762854
min 13.000000 0.000000 0.000000 0.000000
25% 17.000000 0.000000 1.234300 0.033800
50% 17.000000 0.000000 4.031900 0.991300
75% 18.000000 5.000000 6.495300 2.594000
max 23.000000 14.000000 15.770700 6.948600
View a distribution of the hour of daily peak burn, which looks like this:
print(report['peak_hr'].value_counts().sort_index())
peak_time
13 1
14 2
15 4
16 10
17 53
18 23
19 14
20 1
23 1
Name: count, dtype: int64
From here, the outputs can be converted to any datatype for further analysis or plotted for visualization.
Appendix: Timezone
This section will cover how to determine the UTC offset of a Local Standard Time (LST) based on a date and location (latitude and longitude). This only applies to datasets that are known to be recorded using LST, and is not a substitute in cases where a dataset's UTC offset is unknown.
The 'timezonefinder' and 'pytz' packages have functions to get the timezone of the weather station based on latitude and longitude.
from datetime import datetime
from timezonefinder import TimezoneFinder
from pytz import timezone
First, make a dataframe of stations with unique ID, latitude, and longitude.
stations = data.loc[:, ['id', 'lat', 'long']].drop_duplicates()
Print the unique station IDs and coordinates. For this dataset the only station is at Petawawa Research Forest (PRF).
print(stations)
id lat long
0 PRF 45.996 -77.427
Find the timezone based on latitude and longitude.
tf = TimezoneFinder()
tz_loc = tf.timezone_at(lat = stations.at[0, 'lat'], lng = stations.at[0, 'long'])
Print timezone location. PRF is equivalent to "America/Toronto".
print(tz_loc)
'America/Toronto'
The UTC offset can then be determined from the timezone location and a date. To guarantee the UTC offset for LST, use a date in winter (e.g. January 1st in the Northern hemisphere or July 1st in the Southern hemisphere).
utc = timezone(tz_loc).localize(datetime(2007, 1, 1)).strftime('%z')
Print UTC offset, PRF in winter is in Eastern Standard Time.
print(utc)
'-0500'
The provided PRF dataset is actually not recorded in LST, but Local Daylight Time (Eastern Daylight Time). This is why the timezone parameter is set to -4, and why this process is not a substitute for actual information about a dataset.