Skip to main content

hEFTy

Some (relatively) lightweight short-term energy forecasting tools for solar, wind, and load.

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).

For solar, look at the notebook solar_example.ipynb for some examples, and more_solar_examples.ipynb for more examples. Both of these convert the resource forecasts to power.

There are also solar ensemble forecasts demonstrated in ensemble_example.ipynb.

For wind, look at the notebook wind_example.ipynb. The wind tools are not as developed at the solar tools.

The 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.

Supported forecast models

The solar, wind, and datetime helper functions use these model names in the model argument. The forecast span is the forecast-hour range available from compatible model cycles. In general, run_length + lead_time_to_start must fit inside the listed span for the selected cycle. Use adjust_forecast_datetimes() to select an initialization time and lead-time combination that satisfies cycle-specific limits. Note that these forecast model schedules/features can change over time, and the get_fcast_definition function in hefty.utilities is intended to record these changes.

Model Forecast type Function support Cycles Available forecast span Forecast-hour steps
hrrr NOAA HRRR deterministic NWP Solar, wind Hourly; 00z, 06z, 12z, and 18z have extended range 0-18 h; extended cycles: 0-48 h 1 h
gfs NOAA GFS deterministic NWP Solar, wind 00z, 06z, 12z, 18z 0-120 h, then 123-384 h 1 h through 120 h, then 3 h
gefs NOAA GEFS ensemble NWP Solar, wind, solar ensemble 00z, 06z, 12z, 18z 0-384 h. Solar uses 0.25 degree data through 240 h when available and 0.5 degree data beyond that. 3 h
ifs ECMWF IFS deterministic NWP Solar, wind 00z, 06z, 12z, 18z; 00z and 12z have extended range 0-144 h; extended cycles: 150-360 h 3 h through 144 h, then 6 h
aifs ECMWF AIFS deterministic MLWP Solar, wind 00z, 06z, 12z, 18z 0-360 h 6 h
cams ECMWF CAMS IFS composition forecast Solar only via get_solar_forecast 00z, 12z 0-120 h. Requires cdsapi and a CDS API key. 1 h
ifs_ens ECMWF IFS ensemble NWP Solar ensemble 00z, 06z, 12z, 18z; 00z and 12z have extended range 0-144 h; extended cycles: 150-360 h 3 h through 144 h, then 6 h
aifs_ens ECMWF AIFS ensemble MLWP Solar ensemble 00z, 06z, 12z, 18z; 00z and 12z have extended range 00z and 12z: 0-360 h; 06z and 18z: 0-144 h 6 h

For ensemble forecasts, get_solar_forecast_ensemble() supports ifs_ens, aifs_ens, and gefs. get_solar_forecast_ensemble_subset() currently supports ifs_ens only.

Custom forecasts use the period, product, and search_str arguments passed to get_custom_forecast(), rather than the model-specific forecast-hour formatter used by the solar and wind tools.

Handling dates and times

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.

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.

As a simplified example, assume a model:

  • initialized at 00Z (midnight UTC) and 06Z, like GFS, GEFS, and IFS
  • has 3 hour native interval length (like GEFS and IFS)
  • and there's a 4.5 hour total delay in delivering outputs.

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.

                                                 Current time
                                                      |
                                                      ↓----lead time---→|====run length===|
            |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | 
Hour (UTC): 00    01    02    03    04    05    06    07    08    09    10    11    12    13    14    15
            |XXXXXXXX 00z delay XXXXXXX|        |
            |f00--------------|f03--------------|f06--------------|f09--------------|f12--------------|f15
            |         00z NWP forecast          |         
            |                                   |
            00z init_date                       |XXXXXXXX 06z delay XXXXXXX|
                                                |f00--------------|f03--------------|f06--------------|f09
                                                |         06z NWP forecast
                                                |
                                                06z init_date         

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:

from hefty.utilities import adjust_forecast_datetimes

init_date, run_length, lead_time_to_start = adjust_forecast_datetimes(
    available_date='2026-04-23 07:00+00:00',
    run_length_needed=3,
    lead_time_to_start_needed=3,
    model='gefs'
)

print(f'init_date: {init_date}')
print(f'run_length: {run_length}')
print(f'lead_time_to_start: {lead_time_to_start}')

with output

init_date: 2026-04-23 00:00:00+00:00
run_length: 6
lead_time_to_start: 9

Those outputs could then be directly passed as inputs to hefty.solar.get_solar_forecast.

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.

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/.

Quick examples

Here's a quick example of getting a solar resource data forecast, assuming you have already determined the dates/times needed:

from hefty.solar import get_solar_forecast

latitude = 33.5
longitude = -86.8
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
resource_data = get_solar_forecast(
    latitude,
    longitude,
    init_date,
    run_length=18, # 18 hours are included in the forecast
    lead_time_to_start=3, # forecast starts 3 hours out from the init_date
    model='hrrr', # use NOAA HRRR
)
resource_data[
    ['ghi','dni','dhi','temp_air','wind_speed']
              ].plot(drawstyle='steps-mid')

with this output:

Here's a wind resource forecast:

from hefty.wind import get_wind_forecast

latitude = 33.5
longitude = -86.8
init_date = '2024-06-05 6:00' # datetime the forecast model was initialized
resource_data = get_wind_forecast(
    latitude,
    longitude,
    init_date,
    run_length=18, # 18 hours are included in the forecast
    lead_time_to_start=3, # forecast starts 3 hours out from the init_date
    model='gfs', # use NOAA GFS
)
resource_data[
    ['wind_speed_10m', 'wind_speed_80m',
    'wind_speed_100m', 'temp_air_2m', 
    'pressure_0m']
    ].plot(secondary_y=['pressure_0m'], drawstyle='steps-mid')

with this output (note that pressure is on the secondary y-axis):

Troubleshooting

GRIB files can occasionally download with missing/incomplete artifacts. If forecasts contain unexpected missing/incomplete values, try deleting cached GRIB files from your Herbie cache. See the Herbie cache configuration docs: https://herbie.readthedocs.io/en/stable/user_guide/configure.html.

If deleting the cache does not resolve the issue, try downloading the same forecast from a different Herbie source, such as Azure, Google, or AWS.

Attribution

ECMWF

If you use models from ECMWF, you may need to include attribution language with the results.

For IFS and AIFS open data (model='ifs' or model='aifs'), please see the ECMWF license terms. For the CAMS version of IFS (model='cams'), please see the References and License sections of the CAMS global atmospheric composition forecasts page.

A possible example attribution for IFS and AIFS:

This document/data/output/Results is/are based on data and products of the European Centre for Medium-Range Weather Forecasts (ECMWF). © 2026 European Centre for Medium-Range Weather Forecasts (ECMWF), www.ecmwf.int. This data is published under a Creative Commons Attribution 4.0 International (CC BY 4.0). https://creativecommons.org/licenses/by/4.0/. ECMWF does not accept any liability whatsoever for any error or omission in the data, their availability, or for any loss or damage arising from their use.

ECMWF Data have been modified using the functions included in the hefty Python package (e.g., interpolation to hourly values).

A possible example attribution and citation for the CAMS version of IFS:

Contains modified Copernicus Atmosphere Monitoring Service information [2026]. Neither the European Commission nor ECMWF is responsible for any use that may be made of the Copernicus information or data it contains. © 2026 European Centre for Medium-Range Weather Forecasts (ECMWF), www.ecmwf.int. This data is published under a Creative Commons Attribution 4.0 International (CC BY 4.0). https://creativecommons.org/licenses/by/4.0/.

Copernicus Atmosphere Monitoring Service (2021): CAMS global atmospheric composition forecasts. Copernicus Atmosphere Monitoring Service (CAMS) Atmosphere Data Store, DOI: 10.24381/04a0b097 (Accessed on DD-MMM-YYYY).

Installation

A virtual environment is strongly recommended. You can install from PyPi with:

pip install hefty

To run the example Jupyter notebooks, you also need jupyter:

pip install jupyter

If you want to use ECMWF CAMS, you also need cdsapi:

pip install cdsapi

References

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].

[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.

[2] https://github.com/pvlib/pvlib-python

[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

[4] https://github.com/blaylockbk/Herbie

[5] https://github.com/williamhobbs/pv-system-model

[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

Metadata

Release files for hefty 0.1.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hefty 0.1.5
File Size Uploaded
hefty-0.1.5.tar.gz 44.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hefty 0.1.5
File Interpreter ABI Platform
hefty-0.1.5-py3-none-any.whl Python 3 none any Details

Total release size: 87.2 kB

Release files / hefty-0.1.5.tar.gz

Download URL hefty-0.1.5.tar.gz
Size 44.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e6f2e9f155ebe5ebaccf7784aa9e0c4f05fe4e43b01c3d51693404889b8ef98b
BLAKE2b-256 checksum
How to use checksums
c41a3564eec53e79ec5cd1db013ee4dfc33aa2e0a8131841af08580a85541517
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release files / hefty-0.1.5-py3-none-any.whl

Download URL hefty-0.1.5-py3-none-any.whl
Size 42.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
29a3e2423794dd355001ebda68098a970263da2398cb76d505c409487101eba7
BLAKE2b-256 checksum
How to use checksums
9275f7884e040fe1519c5cfd13aff7020b52726174e5fe47484cbe4e2c430d94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.9

Release history Release notifications | RSS feed

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.6

2 release files

This release

0.1.5 This release

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page