hefty 0.0.6__tar.gz → 0.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
hefty-0.0.8/PKG-INFO ADDED
@@ -0,0 +1,184 @@
1
+ Metadata-Version: 2.4
2
+ Name: hefty
3
+ Version: 0.0.8
4
+ Summary: Some (relatively) lightweight short-term energy forecasting tools for solar, wind, and load.
5
+ Author: Will Hobbs
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/williamhobbs/hefty
8
+ Project-URL: Issues, https://github.com/williamhobbs/hefty/issues
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering
14
+ Requires-Python: >=3.11
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: herbie-data[extras]>=2026.3.0
18
+ Requires-Dist: pvlib>=0.13.1
19
+ Requires-Dist: pandas>=3.0.0
20
+ Requires-Dist: urllib3>=2.6.0
21
+ Dynamic: license-file
22
+
23
+ # hEFTy
24
+ Some (relatively) lightweight short-term **e**nergy **f**orecasting **t**ools for solar, wind, and load.
25
+
26
+ This repository currently includes solar and wind tools, but may expand one day to include electric load. Forecasts can be created using the NOAA GFS, NOAA GEFS, NOAA HRRR, and ECMWF IFS and AIFS (open data versions) Numerical Weather Prediction (NWP) and Machine Learning Weather Prediction (MLWP) models. The ECMWF CAMS version of IFS is also included, but only via `hefty.solar.get_solar_forecast()`, and it requires `cdsapi` to be installed and the user needs an API key (see https://ads.atmosphere.copernicus.eu/how-to-api).
27
+
28
+ For solar, look at the notebook [solar_example.ipynb](examples/solar_example.ipynb) for some examples, and [more_solar_examples.ipynb](examples/more_solar_examples.ipynb) for more examples. Both of these convert the resource forecasts to power.
29
+
30
+ There are also solar ensemble forecasts demonstrated in [ensemble_example.ipynb](examples/ensemble_example.ipynb).
31
+
32
+ For wind, look at the notebook [wind_example.ipynb](examples/wind_example.ipynb). The wind tools are not as developed at the solar tools.
33
+
34
+ The [custom.py](src/hefty/custom.py) module is intended to help with getting forecasts of "custom" weather parameters, not necessarily specific to wind or solar, which migh be useful for load forecasting.
35
+
36
+ ### Handling dates and times
37
+
38
+ Handling dates and times can get a bit complicated when it comes to forecasts. hefty tries to match conventions used in the Solar Forecast Arbiter (https://forecastarbiter.epri.com/definitions/), such as "_lead time to start_" and "_run length_". However, the Arbiter uses the term "_issue time_" to represent the time that a forecast is issued/delivered, but that time is not necessarily directly relevant to NWP/MLWP outputs.
39
+
40
+ NWP/MLWP models typically have an **initialization time** (a.k.a. initialization date or datetime), which is (roughly) when the model started running, but the models can take many minutes to several hours to run and have output files posted online where hefty can access them.
41
+
42
+ As a simplified example, assume a model:
43
+ - initialized at 00Z (midnight UTC) and 06Z, like GFS, GEFS, and IFS
44
+ - has 3 hour native interval length (like GEFS and IFS)
45
+ - and there's a 4.5 hour total delay in delivering outputs.
46
+
47
+ See the diagram below. If the current time is 07:00 UTC, and you want a forecast that covers 10:00 to 13:00 UTC, that's a desired lead time of 3 hr and a desired run length of 3 hours. Because the 06Z initialization time model run outputs will not be available until after 10:30, you will need to use the 00Z model outputs. And to get forecasted values that cover hours beginning 10:00-12:00 UTC, hefty will need to access the 9-, 12-, and 15-hour ahead outputs (labeled `f09`-`f15` below) from the 00Z forecast, which will be interpolated to hourly and will include the hours of interest.
48
+
49
+ ```
50
+ Current time
51
+ |
52
+ ↓----lead time---→|====run length===|
53
+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
54
+ Hour (UTC): 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
55
+ |XXXXXXXX 00z delay XXXXXXX| |
56
+ |f00--------------|f03--------------|f06--------------|f09--------------|f12--------------|f15
57
+ | 00z NWP forecast |
58
+ | |
59
+ 00z init_date |XXXXXXXX 06z delay XXXXXXX|
60
+ |f00--------------|f03--------------|f06--------------|f09
61
+ | 06z NWP forecast
62
+ |
63
+ 06z init_date
64
+ ```
65
+
66
+ To help with this, hefty includes a helper function in `hefty.utilities` called `adjust_forecast_datetimes`. Here's an example, similar to the illustration above, using GEFS:
67
+
68
+ ```python
69
+ from hefty.utilities import adjust_forecast_datetimes
70
+
71
+ init_date, run_length, lead_time_to_start = adjust_forecast_datetimes(
72
+ available_date='2026-04-23 07:00+00:00',
73
+ run_length_needed=3,
74
+ lead_time_to_start_needed=3,
75
+ model='gefs'
76
+ )
77
+
78
+ print(f'init_date: {init_date}')
79
+ print(f'run_length: {run_length}')
80
+ print(f'lead_time_to_start: {lead_time_to_start}')
81
+ ```
82
+ with output
83
+
84
+ ```
85
+ init_date: 2026-04-23 00:00:00+00:00
86
+ run_length: 6
87
+ lead_time_to_start: 9
88
+ ```
89
+ Those outputs could then be directly passed as inputs to `hefty.solar.get_solar_forecast`.
90
+
91
+ Model delays are more than just a fixed time: they can vary by lead time and by cycle time. And some cycles have different total run lengths and interval size for some models. `adjust_forecast_datetimes` adjusts for all of this for you.
92
+
93
+ Delays calculated in `adjust_forecast_datetimes` are based on experiments in this gist https://gist.github.com/williamhobbs/9585ff5d1248ab5de4d9e8665d7c8ea6 (which will hopefully one day be cleaned up and added to this repo somehow), documentation published by ECMWF, and this cool dashboard by dynamical.org https://dynamical.org/status/.
94
+
95
+ ## Quick examples
96
+
97
+ Here's a quick example of getting a solar resource data forecast, assuming you have already determined the dates/times needed:
98
+
99
+ ```python
100
+ from hefty.solar import get_solar_forecast
101
+
102
+ latitude = 33.5
103
+ longitude = -86.8
104
+ init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
105
+ resource_data = get_solar_forecast(
106
+ latitude,
107
+ longitude,
108
+ init_date,
109
+ run_length=18, # 18 hours are included in the forecast
110
+ lead_time_to_start=3, # forecast starts 3 hours out from the init_date
111
+ model='hrrr', # use NOAA HRRR
112
+ )
113
+ resource_data[
114
+ ['ghi','dni','dhi','temp_air','wind_speed']
115
+ ].plot(drawstyle='steps-mid')
116
+ ```
117
+
118
+ with this output:
119
+
120
+ <img src="images/output.png" width="500"/>
121
+
122
+ Here's a wind resource forecast:
123
+
124
+ ```python
125
+ from hefty.wind import get_wind_forecast
126
+
127
+ latitude = 33.5
128
+ longitude = -86.8
129
+ init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
130
+ resource_data = get_wind_forecast(
131
+ latitude,
132
+ longitude,
133
+ init_date,
134
+ run_length=18, # 18 hours are included in the forecast
135
+ lead_time_to_start=3, # forecast starts 3 hours out from the init_date
136
+ model='gfs', # use NOAA GFS
137
+ )
138
+ resource_data[
139
+ ['wind_speed_10m', 'wind_speed_80m',
140
+ 'wind_speed_100m', 'temp_air_2m',
141
+ 'pressure_0m']
142
+ ].plot(secondary_y=['pressure_0m'], drawstyle='steps-mid')
143
+ ```
144
+ with this output (note that pressure is on the secondary y-axis):
145
+
146
+ <img src="images/output_wind.png" width="500"/>
147
+
148
+ ## Installation
149
+
150
+ A virtual environment is strongly recommended. You can install from PyPi with:
151
+
152
+ ```
153
+ pip install hefty
154
+ ```
155
+
156
+ To run the example Jupyter notebooks, you also need `jupyter`:
157
+
158
+ ```
159
+ pip install jupyter
160
+ ```
161
+
162
+ If you want to use ECMWF CAMS, you also need `cdsapi`:
163
+
164
+ ```
165
+ pip install cdsapi
166
+ ```
167
+
168
+ ## References
169
+ This project uses several Python packages, including pvlib, an open-source solar PV modeling package [1, 2], and Herbie [3, 4], a package for accessing weather forecast data from NOAA. `pv_model.py` (with the `model_pv_power()` function used here) comes from [5] which leverages some functions from [6].
170
+
171
+ <img src="images/pvlib_powered_logo_horiz.png" width="200"/>
172
+
173
+
174
+ [1] Anderson, K., Hansen, C., Holmgren, W., Jensen, A., Mikofski, M., and Driesse, A. “pvlib python: 2023 project update.” Journal of Open Source Software, 8(92), 5994, (2023). [DOI: 10.21105/joss.05994](http://dx.doi.org/10.21105/joss.05994).
175
+
176
+ [2] https://github.com/pvlib/pvlib-python
177
+
178
+ [3] Blaylock, B. K. (2025). Herbie: Retrieve Numerical Weather Prediction Model Data (Version 2025.3.1) [Computer software]. https://doi.org/10.5281/zenodo.4567540
179
+
180
+ [4] https://github.com/blaylockbk/Herbie
181
+
182
+ [5] https://github.com/williamhobbs/pv-system-model
183
+
184
+ [6] Hobbs, W., Anderson, K., Mikofski, M., and Ghiz, M. "An approach to modeling linear and non-linear self-shading losses with pvlib." 2024 PV Performance Modeling Collaborative (PVPMC). https://github.com/williamhobbs/2024_pvpmc_self_shade
hefty-0.0.8/README.md ADDED
@@ -0,0 +1,162 @@
1
+ # hEFTy
2
+ Some (relatively) lightweight short-term **e**nergy **f**orecasting **t**ools for solar, wind, and load.
3
+
4
+ This repository currently includes solar and wind tools, but may expand one day to include electric load. Forecasts can be created using the NOAA GFS, NOAA GEFS, NOAA HRRR, and ECMWF IFS and AIFS (open data versions) Numerical Weather Prediction (NWP) and Machine Learning Weather Prediction (MLWP) models. The ECMWF CAMS version of IFS is also included, but only via `hefty.solar.get_solar_forecast()`, and it requires `cdsapi` to be installed and the user needs an API key (see https://ads.atmosphere.copernicus.eu/how-to-api).
5
+
6
+ For solar, look at the notebook [solar_example.ipynb](examples/solar_example.ipynb) for some examples, and [more_solar_examples.ipynb](examples/more_solar_examples.ipynb) for more examples. Both of these convert the resource forecasts to power.
7
+
8
+ There are also solar ensemble forecasts demonstrated in [ensemble_example.ipynb](examples/ensemble_example.ipynb).
9
+
10
+ For wind, look at the notebook [wind_example.ipynb](examples/wind_example.ipynb). The wind tools are not as developed at the solar tools.
11
+
12
+ The [custom.py](src/hefty/custom.py) module is intended to help with getting forecasts of "custom" weather parameters, not necessarily specific to wind or solar, which migh be useful for load forecasting.
13
+
14
+ ### Handling dates and times
15
+
16
+ Handling dates and times can get a bit complicated when it comes to forecasts. hefty tries to match conventions used in the Solar Forecast Arbiter (https://forecastarbiter.epri.com/definitions/), such as "_lead time to start_" and "_run length_". However, the Arbiter uses the term "_issue time_" to represent the time that a forecast is issued/delivered, but that time is not necessarily directly relevant to NWP/MLWP outputs.
17
+
18
+ NWP/MLWP models typically have an **initialization time** (a.k.a. initialization date or datetime), which is (roughly) when the model started running, but the models can take many minutes to several hours to run and have output files posted online where hefty can access them.
19
+
20
+ As a simplified example, assume a model:
21
+ - initialized at 00Z (midnight UTC) and 06Z, like GFS, GEFS, and IFS
22
+ - has 3 hour native interval length (like GEFS and IFS)
23
+ - and there's a 4.5 hour total delay in delivering outputs.
24
+
25
+ See the diagram below. If the current time is 07:00 UTC, and you want a forecast that covers 10:00 to 13:00 UTC, that's a desired lead time of 3 hr and a desired run length of 3 hours. Because the 06Z initialization time model run outputs will not be available until after 10:30, you will need to use the 00Z model outputs. And to get forecasted values that cover hours beginning 10:00-12:00 UTC, hefty will need to access the 9-, 12-, and 15-hour ahead outputs (labeled `f09`-`f15` below) from the 00Z forecast, which will be interpolated to hourly and will include the hours of interest.
26
+
27
+ ```
28
+ Current time
29
+ |
30
+ ↓----lead time---→|====run length===|
31
+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
32
+ Hour (UTC): 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
33
+ |XXXXXXXX 00z delay XXXXXXX| |
34
+ |f00--------------|f03--------------|f06--------------|f09--------------|f12--------------|f15
35
+ | 00z NWP forecast |
36
+ | |
37
+ 00z init_date |XXXXXXXX 06z delay XXXXXXX|
38
+ |f00--------------|f03--------------|f06--------------|f09
39
+ | 06z NWP forecast
40
+ |
41
+ 06z init_date
42
+ ```
43
+
44
+ To help with this, hefty includes a helper function in `hefty.utilities` called `adjust_forecast_datetimes`. Here's an example, similar to the illustration above, using GEFS:
45
+
46
+ ```python
47
+ from hefty.utilities import adjust_forecast_datetimes
48
+
49
+ init_date, run_length, lead_time_to_start = adjust_forecast_datetimes(
50
+ available_date='2026-04-23 07:00+00:00',
51
+ run_length_needed=3,
52
+ lead_time_to_start_needed=3,
53
+ model='gefs'
54
+ )
55
+
56
+ print(f'init_date: {init_date}')
57
+ print(f'run_length: {run_length}')
58
+ print(f'lead_time_to_start: {lead_time_to_start}')
59
+ ```
60
+ with output
61
+
62
+ ```
63
+ init_date: 2026-04-23 00:00:00+00:00
64
+ run_length: 6
65
+ lead_time_to_start: 9
66
+ ```
67
+ Those outputs could then be directly passed as inputs to `hefty.solar.get_solar_forecast`.
68
+
69
+ Model delays are more than just a fixed time: they can vary by lead time and by cycle time. And some cycles have different total run lengths and interval size for some models. `adjust_forecast_datetimes` adjusts for all of this for you.
70
+
71
+ Delays calculated in `adjust_forecast_datetimes` are based on experiments in this gist https://gist.github.com/williamhobbs/9585ff5d1248ab5de4d9e8665d7c8ea6 (which will hopefully one day be cleaned up and added to this repo somehow), documentation published by ECMWF, and this cool dashboard by dynamical.org https://dynamical.org/status/.
72
+
73
+ ## Quick examples
74
+
75
+ Here's a quick example of getting a solar resource data forecast, assuming you have already determined the dates/times needed:
76
+
77
+ ```python
78
+ from hefty.solar import get_solar_forecast
79
+
80
+ latitude = 33.5
81
+ longitude = -86.8
82
+ init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
83
+ resource_data = get_solar_forecast(
84
+ latitude,
85
+ longitude,
86
+ init_date,
87
+ run_length=18, # 18 hours are included in the forecast
88
+ lead_time_to_start=3, # forecast starts 3 hours out from the init_date
89
+ model='hrrr', # use NOAA HRRR
90
+ )
91
+ resource_data[
92
+ ['ghi','dni','dhi','temp_air','wind_speed']
93
+ ].plot(drawstyle='steps-mid')
94
+ ```
95
+
96
+ with this output:
97
+
98
+ <img src="images/output.png" width="500"/>
99
+
100
+ Here's a wind resource forecast:
101
+
102
+ ```python
103
+ from hefty.wind import get_wind_forecast
104
+
105
+ latitude = 33.5
106
+ longitude = -86.8
107
+ init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
108
+ resource_data = get_wind_forecast(
109
+ latitude,
110
+ longitude,
111
+ init_date,
112
+ run_length=18, # 18 hours are included in the forecast
113
+ lead_time_to_start=3, # forecast starts 3 hours out from the init_date
114
+ model='gfs', # use NOAA GFS
115
+ )
116
+ resource_data[
117
+ ['wind_speed_10m', 'wind_speed_80m',
118
+ 'wind_speed_100m', 'temp_air_2m',
119
+ 'pressure_0m']
120
+ ].plot(secondary_y=['pressure_0m'], drawstyle='steps-mid')
121
+ ```
122
+ with this output (note that pressure is on the secondary y-axis):
123
+
124
+ <img src="images/output_wind.png" width="500"/>
125
+
126
+ ## Installation
127
+
128
+ A virtual environment is strongly recommended. You can install from PyPi with:
129
+
130
+ ```
131
+ pip install hefty
132
+ ```
133
+
134
+ To run the example Jupyter notebooks, you also need `jupyter`:
135
+
136
+ ```
137
+ pip install jupyter
138
+ ```
139
+
140
+ If you want to use ECMWF CAMS, you also need `cdsapi`:
141
+
142
+ ```
143
+ pip install cdsapi
144
+ ```
145
+
146
+ ## References
147
+ This project uses several Python packages, including pvlib, an open-source solar PV modeling package [1, 2], and Herbie [3, 4], a package for accessing weather forecast data from NOAA. `pv_model.py` (with the `model_pv_power()` function used here) comes from [5] which leverages some functions from [6].
148
+
149
+ <img src="images/pvlib_powered_logo_horiz.png" width="200"/>
150
+
151
+
152
+ [1] Anderson, K., Hansen, C., Holmgren, W., Jensen, A., Mikofski, M., and Driesse, A. “pvlib python: 2023 project update.” Journal of Open Source Software, 8(92), 5994, (2023). [DOI: 10.21105/joss.05994](http://dx.doi.org/10.21105/joss.05994).
153
+
154
+ [2] https://github.com/pvlib/pvlib-python
155
+
156
+ [3] Blaylock, B. K. (2025). Herbie: Retrieve Numerical Weather Prediction Model Data (Version 2025.3.1) [Computer software]. https://doi.org/10.5281/zenodo.4567540
157
+
158
+ [4] https://github.com/blaylockbk/Herbie
159
+
160
+ [5] https://github.com/williamhobbs/pv-system-model
161
+
162
+ [6] Hobbs, W., Anderson, K., Mikofski, M., and Ghiz, M. "An approach to modeling linear and non-linear self-shading losses with pvlib." 2024 PV Performance Modeling Collaborative (PVPMC). https://github.com/williamhobbs/2024_pvpmc_self_shade
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hefty"
7
- version = "0.0.6"
7
+ version = "0.0.8"
8
8
  description = "Some (relatively) lightweight short-term energy forecasting tools for solar, wind, and load."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -19,8 +19,10 @@ classifiers = [
19
19
  "Topic :: Scientific/Engineering",
20
20
  ]
21
21
  dependencies = [
22
- "herbie-data[extras] >= 2026.1.0",
22
+ "herbie-data[extras] >= 2026.3.0",
23
23
  "pvlib >= 0.13.1",
24
+ "pandas >= 3.0.0",
25
+ "urllib3 >= 2.6.0",
24
26
  ]
25
27
  license = "BSD-3-Clause"
26
28
  license-files = ["LICENSE*"]
@@ -0,0 +1,11 @@
1
+ import importlib.metadata
2
+
3
+ __version__ = importlib.metadata.version(__package__ or __name__)
4
+
5
+ from hefty import(
6
+ solar,
7
+ pv_model,
8
+ utilities,
9
+ wind,
10
+ custom,
11
+ )
@@ -7,8 +7,8 @@ import time
7
7
 
8
8
  def get_custom_forecast(latitude, longitude, init_date, run_length,
9
9
  lead_time_to_start=0, period=3, model='gfs',
10
- product='pgrb2.0p25', search_str=':TMP:2 m above',
11
- member=None, attempts=2, hrrr_hour_middle=True,
10
+ product='pgrb2.0p25', search_str=':TMP:2 m above',
11
+ member='avg', attempts=2, hrrr_hour_middle=True,
12
12
  hrrr_coursen_window=None, priority=None):
13
13
  """
14
14
  Get a custom forecast for one or several sites from one of several
@@ -40,11 +40,16 @@ def get_custom_forecast(latitude, longitude, init_date, run_length,
40
40
  than or equal to 384.
41
41
 
42
42
  model : string, default 'gfs'
43
- Forecast model. Default is NOAA GFS ('gfs'), but can also be
44
- ECMWF IFS ('ifs'), NOAA HRRR ('hrrr'), or NOAA GEFS ('gefs).
45
-
46
- member: string or int
47
- For models that are ensembles, pass an appropriate single member label.
43
+ Forecast model. Default is NOAA GFS ('gfs'), but can also be ECMWF IFS
44
+ single ('ifs'), ECMWF AIFS single ('aifs'), NOAA HRRR ('hrrr'), or
45
+ NOAA GEFS ('gefs') (a single member from the ensemble).
46
+
47
+ member: string or int, default 'avg'
48
+ For models that are ensembles (GEFS is the only current option),
49
+ pass an appropriate single member label. See Herbie documentation for
50
+ details [1]_. Options for GEFS include 'avg' or 'mean' (the ensemble
51
+ mean), 0 or 'c00' (control member), and 1-30 or 'p01'-'p30' for the 30
52
+ individual members.
48
53
 
49
54
  attempts : int, optional
50
55
  Number of times to try getting forecast data. The function will pause