Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1db4732
draft pvlib prototype
Nov 28, 2024
4a6a702
update pvlib function to work with refactor
Dec 4, 2024
7871cbe
move pvlib functions to separate path
Dec 4, 2024
3ad4ccb
add retrieve sam function
Dec 4, 2024
dcb8bd9
wrap PVSystem
Dec 7, 2024
5bd21c4
basic wrapper draft
Dec 7, 2024
c870e91
kwarg parameters
Dec 7, 2024
c24e0fd
add model chain config class
Dec 11, 2024
ed631a6
refactor to use xarrays
Dec 12, 2024
c205ae0
account for negatives in ac series
Dec 19, 2024
fa49efd
add era5 download variable for precipitable water
Dec 19, 2024
e698fd7
Merge branch 'master' of https://github.com/GeodataTools/geodata into…
Dec 19, 2024
36c158a
add tcwv to era5 rename statement
Dec 24, 2024
e6fe735
move rename statement
Dec 24, 2024
6027f6e
update pvlib function to use tcwv
Dec 24, 2024
c52de27
missing comma
Dec 24, 2024
447ea38
rename to precipitable_water
Jan 7, 2025
a480128
revert addition of relative humidity
Jan 7, 2025
d6c25f5
add relative humidity and precipitable water calculations to pvlib fu…
Jan 14, 2025
36233eb
more tweak related to precipitable water
Jan 17, 2025
92c37b1
Merge branch 'master' of https://github.com/GeodataTools/geodata into…
Jan 17, 2025
0eaf4d5
add ruff dependencies
Jan 17, 2025
be3fa45
linting
Jan 17, 2025
c6cb373
fix missing dependencies in pytest
Jan 19, 2025
344582e
description typo
Jan 21, 2025
ea3e4dc
read the docs notation
Jan 23, 2025
357d51c
additional documentation
Jan 25, 2025
d031144
descriptions + remove dc output for now
Feb 5, 2025
af0a2bf
update copyright info
Feb 9, 2025
0e8427e
update install statements
Feb 9, 2025
4da3e66
example notebook for pvlib
Feb 27, 2025
1b78041
comparison notebook
Mar 18, 2025
6dacba9
update pvlib model output to include pv capacity
Apr 3, 2025
0d3d49c
remove notebook
Apr 5, 2025
6821cbf
add pvlib docs
May 24, 2025
dc841d6
doc tweak
May 24, 2025
2838aeb
[fix] update file paths in weather_data_config for ERA5 data
BillChen24 Aug 28, 2025
d0eeb4b
[fix]: update pvlib_model variable name 'd2m' and correct np.Inf usage
BillChen24 Aug 28, 2025
f9a7575
[fix]: update pvlib 'd2m' variable
BillChen24 Aug 28, 2025
301dac0
[fix] misnamed function
BillChen24 Aug 29, 2025
3800c1e
Fix formatting issues in README.md
BillChen24 Dec 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dev_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ jobs:
run: |
pip install pytest
pip install setuptools
pip install -e ".[download]"
pip install -e ".[download, pvlib]"
pytest tests/dev/
2 changes: 1 addition & 1 deletion .github/workflows/pr_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,5 @@ jobs:
run: |
pip install pytest
pip install setuptools
pip install -e ".[download]"
pip install -e ".[download, pvlib]"
pytest tests/pr/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
GEODATA
-
-

[![DOI](https://zenodo.org/badge/218690319.svg)](https://zenodo.org/badge/latestdoi/218690319)

Expand Down
3 changes: 3 additions & 0 deletions docs/source/datasets/era5/era5_outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
* Wind generation time-series (`wind`)
* Wind speed time-series (`windspd`)
* Solar photovoltaic generation time-series (`pv`)
* Solar photovoltaic generation time-series using the `pvlib` library (`pvlib`). For information on using `pvlib` with `geodata`, see: [era5_pvlib.py](https://github.com/GeodataTools/geodata/blob/master/docs/source/datasets/era5/era5_pvlib.md).



## Supported ERA5 Outputs

Expand Down
89 changes: 89 additions & 0 deletions docs/source/datasets/era5/era5_pvlib.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Generating PV Outputs with `pvlib`

**geodata** also supports solar photovoltaic (PV) generation modeling using the `pvlib` library, integrating solar position, irradiance, and PV system modeling with flexible configuration options.

For more information on `pvlib`, see: [pvlib-python.readthedocs.io](https://pvlib-python.readthedocs.io/en/stable/)

## Supported PV Output


### Solar Photovoltaic Generation Time-series (`pvlib_model`)

Convert ERA5 data into PV generation estimates using `pvlib` functionality.

```python
pvlib_model(
cutout,
system,
model_chain_config,
vars = [
'influx_diffuse',
'influx_direct',
'dewpoint_temperature',
'temperature',
'wnd100m'
]
) -> xarray.Dataset
```

#### Parameters

* `cutout` - `xr.Dataset` - An input ERA5 cutout with the following variables:
- **influx_diffuse** (*float*) - Diffuse horizontal irradiance.
- **influx_direct** (*float*) - Direct normal irradiance.
- **dewpoint_temperature** (*float*) - Dewpoint temperature in Celsius.
- **temperature** (*float*) - Air temperature in Celsius.
- **wnd100m** (*float*) - Wind speed at 100m.
* `system` - A `PVSystem` class defined by `pv_system()`, describing the collection and interactions of PV system components to be used in modeling.
* `model_chain_config` - A `ModelChainConfig` class that defines pvlib ModelChain parameters that can be passed to one or more instances of pvlib_model(). Allows reuse of a common set of ModelChain parameters across multiple PVSystems or even multiple cutouts.
*Note*: For full information on input parameters for the `PVSystem` and `ModelChainConfig` classes, [see the docstrings here.](https://github.com/GeodataTools/geodata/blob/master/src/geodata/pvlib.py)


#### Output

* Outputs an `xarray.Dataset` containing:
- **ac** (*float*) - AC photovoltaic output (W).
- **pv** (*float*) - Photovoltaic capacity.

#### Example Code and Result

```python
n_mods = 50
n_strings = 1
cec_modules = geodata.pvlib.retrieve_sam('CECMod')
module = cec_modules['Kaneka_U_SA105']
inv = geodata.pvlib.retrieve_sam("CECInverter")['Fronius_USA__CL_33_3_Delta__208V_']

system = geodata.pvlib.pv_system(
arrays = None,
surface_tilt=35,
surface_azimuth=180,
racking_model = 'open_rack',
module_parameters=module,
modules_per_string = n_mods,
module_type = 'glass_polymer',
module = 'Kaneka_U_SA105',
strings_per_inverter = n_strings,
inverter_parameters=inv
)

model_config = geodata.pvlib.ModelChainConfig(
clearsky_model= 'haurwitz',
transposition_model='perez',
solar_position_method= 'nrel_numpy',
airmass_model= 'kastenyoung1989',
dc_model='cec',
ac_model='sandia',
aoi_model="physical",
spectral_model='first_solar',
dc_ohmic_model='no_loss'
)

model = geodata.pvlib.pvlib_model(
cutout,
system,
model_config
)
model

```
264 changes: 264 additions & 0 deletions example_notebooks/geodata_pvlib.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a6947bae-0da5-4758-8816-e30e8de35b11",
"metadata": {},
"source": [
"# Pvlib Generation Process\n",
"\n",
"This Jupyter notebook provides a brief overview of how to use the embedded **pvlib** functionality \n",
"within the **geodata** package to create photovoltaic energy series using **geodata** cutouts.\n",
"\n",
"*The following guide assumes you have installed and configured **geodata** and all required dependencies, \n",
"and have also installed the **pvlib** module.*\n",
"\n",
"For a guide on how to install **pvlib**, see the [pvlib documentation](https://pvlib-python.readthedocs.io/en/stable/user_guide/installation.html#editablelibrary).\n"
]
},
{
"cell_type": "markdown",
"id": "4bdfea85-41ce-48a3-b19b-c11556ad49fa",
"metadata": {},
"source": [
"## Step 1 - Download and Create an ERA5 Cutout\n",
"\n",
"Assuming you have previously created a CDS account and set up the CDS API credentials, you can download ERA5 data from the CDS API as follows.\n",
"\n",
"First, define a dataset object for the data you wish to download:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e1c36475-ea3e-47ca-8f18-6cd0b28378ba",
"metadata": {},
"outputs": [],
"source": [
"import geodata\n",
"\n",
"DS = geodata.Dataset(\n",
" module=\"era5\",\n",
" weather_data_config=\"wind_solar_hourly\",\n",
" years=slice(2009, 2009),\n",
" months=slice(5, 6),\n",
" bounds=[50, -3, 45, 3]\n",
")\n",
"\n",
"if DS.prepared == False:\n",
" DS.get_data()\n",
"\n",
"cutout = geodata.Cutout(\n",
" name=\"era5-europe-test-2009-56\",\n",
" module=\"era5\",\n",
" weather_data_config=\"wind_solar_hourly\",\n",
" ys=slice(1, 2), \n",
" xs=slice(47, 48), \n",
" years=slice(2009, 2009),\n",
" months=slice(5, 6),\n",
")\n",
"cutout.prepare(overwrite=True)"
]
},
{
"cell_type": "markdown",
"id": "35e9bc2a-e224-4a3b-81f9-f84a821f05a6",
"metadata": {},
"source": [
"* Specify \"era5\" as the model, with a `weather_data_config` of \"wind_solar_hourly\" (this is currently the only configuration supported by **pvlib** functionality in **geodata**.\n",
"* PV data will be generated at the hourly level for each set of coordinates included in the specified bounds, over the specified time period."
]
},
{
"cell_type": "markdown",
"id": "c1ff4b5f-a652-47a7-a404-733f3a152b62",
"metadata": {},
"source": [
"## Step 2 - Define PV system and model parameters\n",
"\n",
"In order to generate PV data, you must first define parameters for both the PV system and the PV model.\n",
"First, define system parameters as per the following example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "574aecf4-3c32-4260-a190-9d0980fe4c68",
"metadata": {},
"outputs": [],
"source": [
"n_mods = 50\n",
"n_strings = 1\n",
"cec_modules = geodata.pvlib.retrieve_sam('CECMod')\n",
"module = cec_modules['Kaneka_U_SA105']\n",
"inv = geodata.pvlib.retrieve_sam(\"CECInverter\")['Fronius_USA__CL_33_3_Delta__208V_']\n",
"\n",
"system = geodata.pvlib.pv_system(\n",
" arrays = None,\n",
" surface_tilt=35,\n",
" surface_azimuth=180,\n",
" racking_model = 'open_rack',\n",
" module_parameters=module,\n",
" modules_per_string = n_mods,\n",
" module_type = 'glass_polymer',\n",
" module = 'Kaneka_U_SA105',\n",
" strings_per_inverter = n_strings, \n",
" inverter_parameters=inv\n",
")"
]
},
{
"cell_type": "markdown",
"id": "915ab2d1-f5e6-4ade-8422-44e21663e27a",
"metadata": {},
"source": [
"For a full list of module and inverter info available for use, see: [pvlib.pvsystem.retrieve_sam()](https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.retrieve_sam.html#pvlib.pvsystem.retrieve_sam)\n",
"\n",
"For comprehensive documentation on parameters used to define a PV system with **pvlib**, see: [pvlib.pvsystem.PVSystem()](https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.pvsystem.PVSystem.html)"
]
},
{
"cell_type": "markdown",
"id": "333249a8-8efd-4996-a7b9-55c74a798e11",
"metadata": {},
"source": [
"Next, define the PV model parameters as follows:"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b1d78e83-c1fc-4b29-b155-56678f300def",
"metadata": {},
"outputs": [],
"source": [
"model_config = geodata.pvlib.ModelChainConfig(\n",
" clearsky_model= 'haurwitz',\n",
" transposition_model='perez', \n",
" solar_position_method= 'nrel_numpy',\n",
" airmass_model= 'kastenyoung1989',\n",
" dc_model='cec',\n",
" ac_model='sandia', \n",
" aoi_model=\"physical\",\n",
" spectral_model='first_solar',\n",
" dc_ohmic_model='no_loss'\n",
")"
]
},
{
"cell_type": "markdown",
"id": "86fa0a15-11a2-4347-9df0-4d3ba2bb0e33",
"metadata": {},
"source": [
"For a comprehensive documentation on parameters used to define a PV model with **pvlib**, see: [pvlib.modelchain.ModelChain](https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.modelchain.ModelChain.html#pvlib.modelchain.ModelChain)"
]
},
{
"cell_type": "markdown",
"id": "9a0c7170-1ead-4978-8fd7-0675ecd7ea91",
"metadata": {},
"source": [
"## Step 3 - Run PV model using cutout\n",
"\n",
"The model can then be run as follows:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f839dd15-d6f5-420f-985c-dc45829fb8d5",
"metadata": {},
"outputs": [],
"source": [
"model = geodata.pvlib.pvlib_model(\n",
" cutout,\n",
" system,\n",
" model_config\n",
")\n",
"model"
]
},
{
"cell_type": "markdown",
"id": "47d457ed-9b55-4213-ad21-dec44b8cdee5",
"metadata": {},
"source": [
"If needed, the results can be converted to a Pandas dataframe, and/or graphed:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9b739845-9e54-42b1-936e-e75e16c5f03a",
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": true
}
},
"outputs": [],
"source": [
"model_df = model.to_dataframe()\n",
"print(model_df)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae2cc54a-de32-4d39-b6df-99b99ce733ee",
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import pandas as pd\n",
"x_coord = 47.0\n",
"y_coord = 1.25\n",
"date = '2009-05-02'\n",
"plot_df = model_df.reset_index()\n",
"plot_df = plot_df[\n",
" (plot_df['x'] == x_coord) \n",
" & (plot_df['y'] == y_coord) \n",
" & (plot_df['time'].dt.date == pd.to_datetime(date).date())]\n",
"\n",
"plot_df = plot_df.sort_values(by='time')\n",
"plt.figure(figsize=(10, 5))\n",
"plt.plot(plot_df['time'], plot_df['ac'], marker='o', linestyle='-')\n",
"plt.xlabel('Time')\n",
"plt.ylabel('AC Power Output')\n",
"plt.title(f'AC power output for ({x_coord}, {y_coord} on {date})')\n",
"plt.xticks(rotation=45)\n",
"plt.grid()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a3e81e9c-061c-4f2c-b423-63ed2a1d806e",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ docs = [
"sphinx-book-theme>=1.1.3",
"sphinx-autoapi==3.3.2"
]
pvlib = [
"pvlib>=0.11.2",
"timezonefinder>=6.5.7",
]

[tool.uv]
dev-dependencies = [
Expand Down
Loading
Loading