Please provide a high level description of the feature.
Implement a SolarCalibrator class under rencal/calibration/solar/ that mirrors the structure and workflow of WindCalibrator, adapting the calibration pipeline for solar PV generators. The ERA5 downloader and data loader already support solar variables (ssrd, t2m), so the core data infrastructure is in place. What's needed is the solar-specific calibrator and supporting constants.
Describe the proposed solution and/or implementation in more detail
New files / directories:
rencal/calibration/solar/__init__.py
rencal/calibration/solar/solar_calibrator.py — SolarCalibrator(Calibrator) implementing all abstract methods
Changes to existing files:
rencal/utils/constants.py — add:
SOLAR_TECHNOLOGY_TYPES (analogous to WIND_TECHNOLOGY_TYPES)
- Solar-specific constants (irradiance bounds, curve-fitting params)
SOLAR_NPY_BASEPATH / SOLAR_NPY_HISTOGRAMS_BASEPATH
rencal/core/data_loader.py — extend check_historical_weather(), get_historical_weather(), and get_prefix_histograms() to handle solar NPY paths alongside wind
Key implementation differences from WindCalibrator:
-
Resource variable: Use ssrd (surface solar radiation downwards) as the primary resource proxy instead of wind speed. Note: ssrd is in J/m² (accumulated over the hour) and will need a unit conversion to W/m² (divide by 3600) in extract_resource_timeseries_for_plants().
-
Optional temperature correction: t2m (2m temperature) is also available and could be used to model temperature-dependent efficiency losses.
-
Power curve shape: The wind calibrator uses a generalised logistic (sigmoid) function. Solar load factor is more linearly related to irradiance rather than sigmoidal — curve fitting approach to be determined from internal reference script.
-
Distribution fitting: The wind calibrator fits a Weibull distribution to historical wind speeds. Solar irradiance has a large mass at zero (night-time), making a standard Weibull a poor fit — distribution approach to be determined from internal reference script.
-
NPY output: WindCalibrator has a stream_npy_output flag for writing .npy alongside .parquet. Whether SolarCalibrator should mirror this is left to the implementer.
Describe alternatives you've considered
No alternatives have been formally considered yet. The assumption is the Calibrator abstract base class and LocalDataLoader infrastructure are reused as-is, with only solar-specific logic added.
Additional context (Optional)
The ERA5DataDownloader already downloads ssrd and t2m as part of its solar request and merges them into the same NetCDF as the wind variables. The LocalDataLoader._filter_dataset_variables() already includes DEFAULT_SOLAR_VARIABLES when loading ERA5 data. No changes to the downloader or ERA5 loading pipeline should be required.
Implementation should be modelled from an internal calibration script. The following design questions should be resolved by reference to that script before or during implementation:
- Power curve shape: Should the solar curve use a piecewise-linear / clipped linear fit, or keep the generalised logistic function with different initial parameter bounds? This affects
estimate_load_factors_for_resource() and the constants to add to rencal/utils/constants.py.
- Distribution fitting: Should night-time (zero-irradiance) periods be filtered before fitting, and if so, which distribution should be used (e.g., beta, truncated normal)? Or should a different integration approach be used in
estimate_load_factors_for_resource()?
Please provide a high level description of the feature.
Implement a
SolarCalibratorclass underrencal/calibration/solar/that mirrors the structure and workflow ofWindCalibrator, adapting the calibration pipeline for solar PV generators. The ERA5 downloader and data loader already support solar variables (ssrd,t2m), so the core data infrastructure is in place. What's needed is the solar-specific calibrator and supporting constants.Describe the proposed solution and/or implementation in more detail
New files / directories:
rencal/calibration/solar/__init__.pyrencal/calibration/solar/solar_calibrator.py—SolarCalibrator(Calibrator)implementing all abstract methodsChanges to existing files:
rencal/utils/constants.py— add:SOLAR_TECHNOLOGY_TYPES(analogous toWIND_TECHNOLOGY_TYPES)SOLAR_NPY_BASEPATH/SOLAR_NPY_HISTOGRAMS_BASEPATHrencal/core/data_loader.py— extendcheck_historical_weather(),get_historical_weather(), andget_prefix_histograms()to handle solar NPY paths alongside windKey implementation differences from
WindCalibrator:Resource variable: Use
ssrd(surface solar radiation downwards) as the primary resource proxy instead of wind speed. Note:ssrdis in J/m² (accumulated over the hour) and will need a unit conversion to W/m² (divide by 3600) inextract_resource_timeseries_for_plants().Optional temperature correction:
t2m(2m temperature) is also available and could be used to model temperature-dependent efficiency losses.Power curve shape: The wind calibrator uses a generalised logistic (sigmoid) function. Solar load factor is more linearly related to irradiance rather than sigmoidal — curve fitting approach to be determined from internal reference script.
Distribution fitting: The wind calibrator fits a Weibull distribution to historical wind speeds. Solar irradiance has a large mass at zero (night-time), making a standard Weibull a poor fit — distribution approach to be determined from internal reference script.
NPY output:
WindCalibratorhas astream_npy_outputflag for writing.npyalongside.parquet. WhetherSolarCalibratorshould mirror this is left to the implementer.Describe alternatives you've considered
No alternatives have been formally considered yet. The assumption is the
Calibratorabstract base class andLocalDataLoaderinfrastructure are reused as-is, with only solar-specific logic added.Additional context (Optional)
The
ERA5DataDownloaderalready downloadsssrdandt2mas part of its solar request and merges them into the same NetCDF as the wind variables. TheLocalDataLoader._filter_dataset_variables()already includesDEFAULT_SOLAR_VARIABLESwhen loading ERA5 data. No changes to the downloader or ERA5 loading pipeline should be required.Implementation should be modelled from an internal calibration script. The following design questions should be resolved by reference to that script before or during implementation:
estimate_load_factors_for_resource()and the constants to add torencal/utils/constants.py.estimate_load_factors_for_resource()?