Solar Power Yield Forecast using hefty–PVRADAR integration¶
This notebook demonstrates how to forecast the expected power output of a solar PV plant by combining ECMWF IFS weather forecasts retrieved with the hefty Python package with the PVRADAR modeling framework. The workflow covers plant definition, forecast retrieval, integration of weather inputs, and calculation of expected PV power together with key intermediate model results.
This notebook and analysis have been prepared in collaboration with Will Hobbs, developer of the hefty Python package.
# Installing required packages automatically
# Note: you may need to restart the kernel to use updated packages.
%pip install -q hefty==0.3.2 dynamical-catalog cartopy nbformat plotly
import pandas as pd
from pvradar.sdk import H, PvradarSite, R, make_fixed_design, make_tracker_design, resource_plot, require_sdk_version
require_sdk_version('2.18.2')
Define the site¶
The PvradarSite object provides a common interface for the plant location, design, data sources, and modeling results.
### Define location of site
site = PvradarSite(location='Virginia Beach, US')
# site = PvradarSite(location='37.73,-76.02')
site.display_map()
Define forecasting period¶
The forecasting period in this example is limited to 5 days which depends on the forecasting service being used (IFS in this case). Also the forecast detail changes depending on the run length.
You can learn more on data availability and forecast delays here:
- https://github.com/williamhobbs/hefty#handling-dates-and-times
- https://github.com/williamhobbs/hefty/blob/main/docs/forecast_model_delays.md
Currently PVRADAR supports all 5 non-ensemble models available in hefty:
hrrr: NOAA HRRR deterministic NWPgfs: NOAA GFS deterministic NWPifs: ECMWF IFS deterministic NWPaifs: ECMWF AIFS deterministic MLWPcams- ECMWF CAMS IFS composition forecast
### Define forecasting model and period
analysis_start = pd.Timestamp.now(tz=site.default_tz).normalize() # today
# analysis_start = pd.Timestamp('2026-09-16', tz=site.default_tz) # fixed date (in the past)
hefty_model = 'ifs'
forecast_days = 5
Ensure the location and and interval is set correctly¶
forecast_end = analysis_start + pd.Timedelta(days=forecast_days)
interval = pd.Interval(left=analysis_start, right=forecast_end, closed='both')
site.interval = interval
site
Pvradar site at (36.8496579, -75.9760751, tz="Etc/GMT+5") with interval [2026-10-03 00:00:00-05:00, 2026-10-08 00:00:00-05:00]
Define PV plant design¶
PVRADAR supports different levels of detail when defining a PV power plant, depending on the purpose of the analysis.
For a quick evaluation, a simplified plant design can be created from only a few key parameters such as the DC capacity, module power, tracking configuration, and DC/AC ratio. This is the approach used in this example.
For more detailed applications, PVRADAR can represent complex plant topologies as digital twins, including thousands of individual components and their relationships. These digital twins can also be created automatically from existing design documentation such as PDFs, Excel files, DWGs, and PVSyst projects.
site.design = make_tracker_design(
rated_array_power_dc=55_000_000, # Wp
rated_module_power=520, # W
max_tracking_angle=55, # deg
dc_ac_ratio=1.2,
backtracking=True,
axis_height= 1.8, # m
module_placement='1v'
)
# site.design = make_fixed_design(...)
# site.design.display_flowchart()
Get forecast using hefty¶
PVRADAR can work with public, third-party, and internal data sources through a common interface.
In this example, we use the hefty Python package to retrieve a ECMWF IFS solar forecast and make it available as an input to the PVRADAR model chain.
All models (except for CAMS IFS) use dynamical.org as a data source
hefty_solar_table = site.run('get_hefty_solar_table', hefty_model=hefty_model)
Review the forecasted data¶
Here resource_plot() function from PVRADAR automatically groups the data by unit
and reads the labels from the metadata
All time series are automatically converted into the local timezone of the power plant
resource_plot(hefty_solar_table)
Modeling expected PV yield with PVRADAR¶
First, we tell PVRADAR to take the weather inputs (irradiance, air temperature and wind speed) from the Hefty forecast instead of the default sources. This is configured once for the whole block.
After that, any time series (resource) can be requested with a single line of code. A full list of available resouces can be found here.
with site.hooks(
H.for_resource({ 'resource_type': 'hefty_solar_table' }).use(hefty_solar_table),
H.for_resource(R.global_horizontal_irradiance).use_model('hefty_global_horizontal_irradiance'),
H.for_resource(R.air_temperature).use_model('hefty_air_temperature'),
H.for_resource(R.wind_speed).use_model('hefty_wind_speed'),
), site.use_profiler() as profiler:
power = site.resource(R.grid_power, label='forecasted power')
tracker_rotation = site.resource(R.tracker_rotation_angle, label='optimal tracking angle')
module_temperature = site.resource(R.module_temperature, label='forecasted module temperature')
resource_plot(power, module_temperature, tracker_rotation)
Visualize model chain¶
PVRADAR resolves all intermediate steps of the model execution plant (model chain) automatically
Here's the model chain for the last resource that was calculated, in this example it is the module_temperature.
# profiler.display_flowchart()
Data attribution¶
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 and pvradar Python packages (e.g., interpolation to hourly values).
