RenCal (Renewable Calibration) is a Python library for calibrating renewable energy power curves and generating probabilistic load-factor time series for wind and solar plants.
It supports Monte Carlo-based forecasting using weather, generation, and plant characteristic data. RenCal is intended for energy analysts, researchers, and developers working on renewable-energy modelling.
RenCal is an experimental pre-1.0 public package. The API and modelling approach may change as the project develops. It is not currently a guarantee of production suitability or a substitute for independent validation.
RenCal is available on PyPI. Install it with your preferred Python package manager:
uv add rencalpython -m pip install rencalgit clone https://github.com/LCCC-Tech/rencal.git
cd rencal
uv sync --group devSee the development setup for the full contributor workflow.
The following example downloads the inputs, calibrates wind streams, and generates a random sample using RenCal's default data directory. Downloads use the Copernicus Climate Data Store (CDS), so you need your own CDS credentials, network access, and permission to access the requested data.
Set the API key in your environment before running the script:
export CDS_API_KEY="your-cds-api-key"Alternatively, pass the key directly to DownloadManager. Never commit API
keys to source control.
importdatetimeimportrandomimportnumpyasnpfromrencal.calibration.wind.wind_calibratorimportWindCalibratorfromrencal.core.data_loaderimportLocalDataLoaderfromrencal.core.data_downloaderimportDownloadManagerfromrencal.simulation.weather_dataimportHistoricalMetadata, WeatherDatadefmain():
# Uses CDS_API_KEY from the environment. Alternatively:# downloader = DownloadManager(cds_api_key="your-cds-api-key")downloader=DownloadManager()
downloader.download_all()
loader=LocalDataLoader()
plants=loader.load_plant_data()
generation=loader.load_generation_data()
print(f"Loaded {len(plants.data)} plants")
print(f"Loaded {len(generation.data)} generation records")
calibrator=WindCalibrator(
output_path="wind-calibration",
visual_output=True,
stream_npy_output=True,
)
calibrator.calibrate()
manifest=loader.check_historical_weather()
metadata=HistoricalMetadata.from_manifest(
manifest,
loader.path_resolver_weather_data,
)
wind_sampler=WeatherData(
metadata=metadata,
prefix_histograms=loader.get_prefix_histograms(),
historical_data=loader.get_historical_weather(),
)
sample=wind_sampler.random_sample(
datetime.datetime(2027, 1, 1),
datetime.datetime(2027, 1, 7),
python_rng=random.Random(4),
numpy_rng=np.random.default_rng(32),
)
print(sample)
if__name__=="__main__":
main()download_all() downloads the CfD, generation, and ERA5 inputs. If you already
have the plant and generation data, use download_era5() to download only the
weather data:
downloader=DownloadManager() # Uses CDS_API_KEY from the environmentdownloader.download_era5()The primary modelling workflow can instead use data supplied by you. RenCal does not distribute operational ERA5, generation, or plant datasets.
frompathlibimportPathfromrencal.core.data_loaderimportLocalDataLoaderloader=LocalDataLoader(data_path=Path("data"))
plants=loader.load_plant_data()
generation=loader.load_generation_data()
print(f"Loaded {len(plants.data)} plants")
print(f"Loaded {len(generation.data)} generation records")For the full wind-calibration workflow, provide the expected input structure:
data/
├── plant/plant_data.csv
├── generation/generation_data.parquet
└── era5/*.nc
The ERA5 loader expects suitable NetCDF weather data. Users are responsible for obtaining data, checking its provenance and licence, and preparing it for the documented schema.
With the plant, generation, and ERA5 inputs in place, run the wind calibration workflow and write its outputs to a separate directory:
frompathlibimportPathfromrencal.calibration.wind.wind_calibratorimportWindCalibratorcalibrator=WindCalibrator(
data_path="data",
output_path=Path("outputs/wind-calibration"),
visual_output=True,
stream_npy_output=True,
)
calibrator.calibrate()The workflow writes the calibration summary, Weibull parameters, extracted wind
speeds, calibrated wind streams, and optional power-curve plots to the output
directory. With stream_npy_output=True, the generated Wind Streams.npy can
also be used by the weather sampler after its manifest and optional histogram
artefacts have been prepared.
WeatherData samples future hourly paths from calibrated historical streams
while preserving the configured time-bucket structure. The local loader expects
the calibrated NPY file and its manifest under data/calibrated/.
importdatetimeimportrandomimportnumpyasnpfromrencal.core.data_loaderimportLocalDataLoaderfromrencal.simulation.weather_dataimportHistoricalMetadata, WeatherDataloader=LocalDataLoader(data_path="data")
manifest=loader.check_historical_weather()
metadata=HistoricalMetadata.from_manifest(
manifest,
loader.path_resolver_weather_data,
)
wind_sampler=WeatherData(
metadata=metadata,
prefix_histograms=loader.get_prefix_histograms(),
historical_data=loader.get_historical_weather(),
)
sample=wind_sampler.random_sample(
datetime.datetime(2027, 1, 1),
datetime.datetime(2027, 1, 7),
python_rng=random.Random(4),
numpy_rng=np.random.default_rng(32),
)Pass desired_averages to WeatherData when inverse-distribution resampling is
required; this also requires historical data or precomputed prefix histograms.
- Wind and solar power-curve calibration foundations
- Probabilistic load-factor forecasting
- Weather and generation data loading and validation
- Time-bucketed sampling with geographical correlation support
- Extensible interfaces for local and external data sources
Hosted documentation and versioned examples will be linked here once the public documentation site is verified.
Use GitHub Issues for public, reproducible bugs and feature requests. Please do not include credentials, internal data, or confidential information in issues.
RenCal is released under the MIT Licence.