Calculate fuel moisture and fire danger indices using this python interface to the NFDRS4 C++ library.
This library offers a simple interface to NFDRS4 and easier installation for Python users. Compilation was tested with Microsoft Visual Studio 2022 with C++ developer workload. Create a github issue if you have problems with installation or otherwise.
Core code forked from https://github.com/firelab/NFDRS4
See also: https://github.com/j-tenny/pyrothermel
Ensure that you have a C++ compiler installed and configured, then run
pip install nfdrs4py
Or clone this repository, cd to the project root, then run pip install .
import nfdrs4py
import pandas as pd
import requests
import iowx = pd.read_csv('data/241513_2001_2017.fw21')
wx.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}
| DateTime | Temperature(F) | RelativeHumidity(%) | Precipitation(in) | WindSpeed(mph) | WindAzimuth(degrees) | SolarRadiation(W/m2) | SnowFlag | GustSpeed(mph) | GustAzimuth(degrees) | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2001-03-22T15:00:00-07:00 | 62.0 | 16.0 | 0.0 | 4.0 | 6.0 | 650.0 | 1.0 | 8.0 | 34.0 | 
| 1 | 2001-03-22T16:00:00-07:00 | 58.0 | 15.0 | 0.0 | 2.0 | 69.0 | 188.0 | 1.0 | 7.0 | 60.0 | 
| 2 | 2001-03-22T17:00:00-07:00 | 60.0 | 12.0 | 0.0 | 5.0 | 270.0 | 93.0 | 1.0 | 16.0 | 243.0 | 
| 3 | 2001-03-22T18:00:00-07:00 | 58.0 | 12.0 | 0.0 | 7.0 | 278.0 | 178.0 | 1.0 | 19.0 | 258.0 | 
| 4 | 2001-03-22T19:00:00-07:00 | 57.0 | 10.0 | 0.0 | 8.0 | 300.0 | 26.0 | 1.0 | 13.0 | 289.0 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 143019 | 2017-12-31T19:00:00-07:00 | 18.0 | 93.0 | 0.0 | 0.0 | 196.0 | 0.0 | NaN | 0.0 | 186.0 | 
| 143020 | 2017-12-31T20:00:00-07:00 | 18.0 | 93.0 | 0.0 | 0.0 | 241.0 | 0.0 | NaN | 0.0 | 340.0 | 
| 143021 | 2017-12-31T21:00:00-07:00 | 17.0 | 90.0 | 0.0 | 0.0 | 215.0 | 0.0 | NaN | 0.0 | 254.0 | 
| 143022 | 2017-12-31T22:00:00-07:00 | 17.0 | 92.0 | 0.0 | 0.0 | 196.0 | 0.0 | NaN | 0.0 | 224.0 | 
| 143023 | 2017-12-31T23:00:00-07:00 | 17.0 | 92.0 | 0.0 | 0.0 | 220.0 | 0.0 | NaN | 0.0 | 206.0 | 
143024 rows × 10 columns
interface = nfdrs4py.NFDRS4py.init_from_config('data/NFDRSInitSample.txt')
results = interface.process_df(wx,0,1,2,3,6,4,7)
results.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}
| DateTime | Temperature(F) | RelativeHumidity(%) | Precipitation(in) | WindSpeed(mph) | WindAzimuth(degrees) | SolarRadiation(W/m2) | SnowFlag | GustSpeed(mph) | GustAzimuth(degrees) | ... | dmc_100_hr | dmc_1000_hr | lmc_herb | lmc_woody | burning_index | energy_release_component | spread_component | ignition_component | growing_season_index | kb_drought_index | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2001-03-22T15:00:00-07:00 | 62.0 | 16.0 | 0.0 | 4.0 | 6.0 | 650.0 | 1.0 | 8.0 | 34.0 | ... | 29.999996 | 20.0 | 30.0 | 60.0 | 0.0 | 3.308081 | 0.0 | 0.0 | 0.0 | 100.0 | 
| 1 | 2001-03-22T16:00:00-07:00 | 58.0 | 15.0 | 0.0 | 2.0 | 69.0 | 188.0 | 1.0 | 7.0 | 60.0 | ... | 29.999966 | 20.0 | 30.0 | 60.0 | 0.0 | 1.858711 | 0.0 | 0.0 | 0.0 | 100.0 | 
| 2 | 2001-03-22T17:00:00-07:00 | 60.0 | 12.0 | 0.0 | 5.0 | 270.0 | 93.0 | 1.0 | 16.0 | 243.0 | ... | 29.999914 | 20.0 | 30.0 | 60.0 | 0.0 | 1.060471 | 0.0 | 0.0 | 0.0 | 100.0 | 
| 3 | 2001-03-22T18:00:00-07:00 | 58.0 | 12.0 | 0.0 | 7.0 | 278.0 | 178.0 | 1.0 | 19.0 | 258.0 | ... | 29.999834 | 20.0 | 30.0 | 60.0 | 0.0 | 0.824433 | 0.0 | 0.0 | 0.0 | 100.0 | 
| 4 | 2001-03-22T19:00:00-07:00 | 57.0 | 10.0 | 0.0 | 8.0 | 300.0 | 26.0 | 1.0 | 13.0 | 289.0 | ... | 29.999721 | 20.0 | 30.0 | 60.0 | 0.0 | 0.782769 | 0.0 | 0.0 | 0.0 | 100.0 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 143019 | 2017-12-31T19:00:00-07:00 | 18.0 | 93.0 | 0.0 | 0.0 | 196.0 | 0.0 | NaN | 0.0 | 186.0 | ... | NaN | NaN | 30.0 | 50.0 | NaN | NaN | NaN | NaN | 0.0 | 100.0 | 
| 143020 | 2017-12-31T20:00:00-07:00 | 18.0 | 93.0 | 0.0 | 0.0 | 241.0 | 0.0 | NaN | 0.0 | 340.0 | ... | NaN | NaN | 30.0 | 50.0 | NaN | NaN | NaN | NaN | 0.0 | 100.0 | 
| 143021 | 2017-12-31T21:00:00-07:00 | 17.0 | 90.0 | 0.0 | 0.0 | 215.0 | 0.0 | NaN | 0.0 | 254.0 | ... | NaN | NaN | 30.0 | 50.0 | NaN | NaN | NaN | NaN | 0.0 | 100.0 | 
| 143022 | 2017-12-31T22:00:00-07:00 | 17.0 | 92.0 | 0.0 | 0.0 | 196.0 | 0.0 | NaN | 0.0 | 224.0 | ... | NaN | NaN | 30.0 | 50.0 | NaN | NaN | NaN | NaN | 0.0 | 100.0 | 
| 143023 | 2017-12-31T23:00:00-07:00 | 17.0 | 92.0 | 0.0 | 0.0 | 220.0 | 0.0 | NaN | 0.0 | 206.0 | ... | NaN | NaN | 30.0 | 50.0 | NaN | NaN | NaN | NaN | 0.0 | 100.0 | 
143024 rows × 22 columns
station_id = '20284'
start_date = '2018-05-23T23:30:00Z'
end_date = '2018-06-03T23:29:59Z'
url = f'https://fems.fs2c.usda.gov/api/climatology/download-weather?stationIds={station_id}&startDate={start_date}&endDate={end_date}&dataset=observation&dataFormat=fw21&dataIncrement=hourly&stationtypes=RAWS(SATNFDRS)'
request = requests.get(url)
wx = pd.read_csv(io.BytesIO(request.content))
wx['SnowFlag'] = wx['SnowFlag'].astype(bool)
wx.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}
| StationId | DateTime | Temperature(F) | RelativeHumidity(%) | Precipitation(in) | WindSpeed(mph) | WindAzimuth(degrees) | GustSpeed(mph) | GustAzimuth(degrees) | SnowFlag | SolarRadiation(W/m2) | Tflag | RHflag | PCPflag | WSflag | WAflag | SRflag | GSflag | GAflag | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 20284 | 2018-05-24T00:00:00-07:00 | 34 | 39 | 0.0 | 2 | 322 | 4 | 217 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 1 | 20284 | 2018-05-24T01:00:00-07:00 | 32 | 42 | 0.0 | 2 | 60 | 3 | 52 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 2 | 20284 | 2018-05-24T02:00:00-07:00 | 29 | 46 | 0.0 | 1 | 212 | 2 | 50 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 3 | 20284 | 2018-05-24T03:00:00-07:00 | 28 | 48 | 0.0 | 1 | 189 | 3 | 12 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 4 | 20284 | 2018-05-24T04:00:00-07:00 | 26 | 56 | 0.0 | 1 | 182 | 4 | 223 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 259 | 20284 | 2018-06-03T19:00:00-07:00 | 79 | 9 | 0.0 | 7 | 216 | 15 | 270 | False | 113.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 260 | 20284 | 2018-06-03T20:00:00-07:00 | 68 | 13 | 0.0 | 3 | 223 | 8 | 216 | False | 4.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 261 | 20284 | 2018-06-03T21:00:00-07:00 | 59 | 18 | 0.0 | 5 | 225 | 6 | 232 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 262 | 20284 | 2018-06-03T22:00:00-07:00 | 52 | 22 | 0.0 | 2 | 355 | 5 | 224 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| 263 | 20284 | 2018-06-03T23:00:00-07:00 | 47 | 25 | 0.0 | 2 | 7 | 3 | 52 | False | 0.0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
264 rows × 19 columns
interface = nfdrs4py.NFDRS4py(Lat=35,FuelModel='W',SlopeClass=1,AvgAnnPrecip=30)results = interface.process_df(wx)
results.dataframe tbody tr th {
    vertical-align: top;
}
.dataframe thead th {
    text-align: right;
}
| StationId | DateTime | Temperature(F) | RelativeHumidity(%) | Precipitation(in) | WindSpeed(mph) | WindAzimuth(degrees) | GustSpeed(mph) | GustAzimuth(degrees) | SnowFlag | ... | dmc_100_hr | dmc_1000_hr | lmc_herb | lmc_woody | burning_index | energy_release_component | spread_component | ignition_component | growing_season_index | kb_drought_index | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 20284 | 2018-05-24T00:00:00-07:00 | 34 | 39 | 0.0 | 2 | 322 | 4 | 217 | False | ... | 19.999734 | 19.999999 | 30.0 | 60.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 100.0 | 
| 1 | 20284 | 2018-05-24T01:00:00-07:00 | 32 | 42 | 0.0 | 2 | 60 | 3 | 52 | False | ... | 19.998554 | 19.999989 | 30.0 | 60.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 100.0 | 
| 2 | 20284 | 2018-05-24T02:00:00-07:00 | 29 | 46 | 0.0 | 1 | 212 | 2 | 50 | False | ... | 19.996832 | 19.999972 | 30.0 | 60.0 | 0.000000 | 0.000000 | 0.528339 | 0.539606 | 0.000000 | 100.0 | 
| 3 | 20284 | 2018-05-24T03:00:00-07:00 | 28 | 48 | 0.0 | 1 | 189 | 3 | 12 | False | ... | 19.994536 | 19.999947 | 30.0 | 60.0 | 0.000000 | 0.000000 | 0.821775 | 0.747045 | 0.000000 | 100.0 | 
| 4 | 20284 | 2018-05-24T04:00:00-07:00 | 26 | 56 | 0.0 | 1 | 182 | 4 | 223 | False | ... | 19.991556 | 19.999915 | 30.0 | 60.0 | 0.000000 | 0.000000 | 0.842248 | 0.747889 | 0.000000 | 100.0 | 
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | 
| 259 | 20284 | 2018-06-03T19:00:00-07:00 | 79 | 9 | 0.0 | 7 | 216 | 15 | 270 | False | ... | 8.521227 | 13.391623 | 30.0 | 60.0 | 43.918018 | 13.209191 | 25.687646 | 50.040193 | 0.074623 | 161.0 | 
| 260 | 20284 | 2018-06-03T20:00:00-07:00 | 68 | 13 | 0.0 | 3 | 223 | 8 | 216 | False | ... | 8.497583 | 13.370282 | 30.0 | 60.0 | 29.707420 | 12.736459 | 11.388582 | 29.923758 | 0.074623 | 161.0 | 
| 261 | 20284 | 2018-06-03T21:00:00-07:00 | 59 | 18 | 0.0 | 5 | 225 | 6 | 232 | False | ... | 8.481125 | 13.355573 | 30.0 | 60.0 | 34.591961 | 12.025729 | 16.792868 | 31.345662 | 0.074623 | 161.0 | 
| 262 | 20284 | 2018-06-03T22:00:00-07:00 | 52 | 22 | 0.0 | 2 | 355 | 5 | 224 | False | ... | 8.639911 | 13.345286 | 30.0 | 60.0 | 23.865936 | 11.142063 | 8.088035 | 18.152894 | 0.074623 | 161.0 | 
| 263 | 20284 | 2018-06-03T23:00:00-07:00 | 47 | 25 | 0.0 | 2 | 7 | 3 | 52 | False | ... | 8.630694 | 13.337515 | 30.0 | 60.0 | 22.471078 | 10.204840 | 7.747199 | 14.670750 | 0.074623 | 161.0 | 
264 rows × 31 columns
results['DateTime'] = pd.to_datetime(results['DateTime'])
results.plot(x='DateTime',y=['dmc_1_hr','dmc_10_hr','dmc_100_hr','dmc_1000_hr'])<Axes: xlabel='DateTime'>
