Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## Unreleased [TBD]

- Add `PySAMWavePerformanceModel` and `WaveResource` to wrap PySAM MhkWave as an H2I performance model, replacing the HOPP wave module in example 09. [PR 825](https://github.com/NatLabRockies/H2Integrate/pull/825)

## 0.9 [August 10, 2026]

### New Features
Expand Down Expand Up @@ -79,6 +83,7 @@
- Corrected water rate units in pipe feedstock from galUS to galUS/h [PR 813](https://github.com/NatLabRockies/H2Integrate/pull/813)
- Corrected timestamps in OpenMeteo resource downloads when resource data is downloaded in local time [PR #814](https://github.com/NatLabRockies/H2Integrate/pull/814)
- Fixed docs build warnings by correcting inline-literal docstring markup etc, also enabled warning-as-error in the shared docs build script to minimize number of future warnings. [PR 821](https://github.com/NatLabRockies/H2Integrate/pull/821)
- Updated edge attribute `commodity` of in `H2Integrate.create_technology_graph` to use lists instead of strings to account for systems with multiple commodities connected between two technologies [PR 823](https://github.com/NatLabRockies/H2Integrate/pull/823)

## 0.8 [April 15, 2026]

Expand Down
7 changes: 4 additions & 3 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,15 @@ met the following steps should be taken to create a new release
1. On `develop`, bump the version appropriately, see the
[semantic versioning guidelines](https://semver.org/) for details.
2. Open a pull request from `develop` into `main`.
3. When all CI tests pass, and the PR has been approved, merge the PR into main.
3. When all CI tests pass, and the PR has been approved, merge the PR into main **and don't squash commits**.
4. Pull the latest changes from GitHub into the local copy of the main branch.
5. Tag the latest commit to match the version bump in step 1 (replace "v0.1" in all instances below),
and push it to the repository.
and push it to the repository. Assuming you have the upstream remote set to the main repository,
you can do this with the following commands:

```bash
git tag -a v0.1 -m "v0.1 release"
git push --origin v0.1
git push upstream v0.1
```

6. Check that the
Expand Down
2 changes: 2 additions & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ parts:
- file: technology_models/marine_hydrokinetic
- file: technology_models/run_of_river
- file: technology_models/tidal
- file: technology_models/wave
- file: technology_models/natural_gas
- file: technology_models/nuclear
- file: technology_models/wombat_electrolyzer_om
Expand Down Expand Up @@ -70,6 +71,7 @@ parts:
- file: resource/meteosat_prime_meridian_v4_api
- file: resource/openmeteo_solar_archive
- file: resource/tidal_resource
- file: resource/wave_resource
- caption: Control
chapters:
- file: control/system_level_control/system_level_control
Expand Down
6 changes: 5 additions & 1 deletion docs/generate_model_overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,16 @@ class CategorySpec:
"h2integrate.resource.wind": ("wind", "wind resource data providers"),
"h2integrate.resource.solar": ("solar", "solar resource data providers"),
"h2integrate.resource.tidal": ("tidal", "tidal resource data providers"),
"h2integrate.resource.wave": ("wave", "wave resource data providers"),
"h2integrate.resource.river": ("river", "river resource data providers"),
# ---- Converters ----
"h2integrate.converters": ("generic", "generic converter components"),
"h2integrate.converters.wind": ("wind", "wind turbine plants"),
"h2integrate.converters.solar": ("solar", "solar-PV panels"),
"h2integrate.converters.water_power": ("water_power", "tidal and run-of-river hydropower"),
"h2integrate.converters.water_power": (
"water_power",
"wave, tidal, and run-of-river hydropower",
),
"h2integrate.converters.hopp": ("hopp", "hybrid renewable plant via HOPP"),
"h2integrate.converters.hydrogen": ("hydrogen", "hydrogen production"),
"h2integrate.converters.hydrogen.geologic": (
Expand Down
50 changes: 50 additions & 0 deletions docs/resource/wave_resource.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(wave_resource)=
# Wave Resource: Model Overview

The wave resource model reads and processes ocean wave data for use in the H2I framework. It expects a CSV file containing timeseries significant wave height (Hs) and energy period (Te) data, and outputs hourly arrays suitable for the {ref}`wave_performance` model.

The wave resource file format follows the [DOE Water Power Technologies Office (WPTO) US Wave Dataset](https://developer.nrel.gov/docs/wave/wave-hindcast-download-v1/) convention. Wave resource files for US coastal locations can be downloaded via the [MHKiT-Python](https://mhkit-software.github.io/MHKiT/) library or the WPTO Hindcast dataset API.

```{note}
H2I expects the wave resource data to be in a timeseries format (not a joint probability distribution).
If the source file contains data at a coarser-than-hourly resolution (e.g., 3-hourly), H2I will
linearly interpolate the values to produce an 8760-hour annual timeseries.
```

## File Format

The wave resource CSV file should be in the following format:

- Row 1: Column names for metadata fields.
- Row 2: Metadata values (latitude, longitude, water depth, data source, etc.).
- Row 3: Column headings for the timeseries data:
`Year`, `Month`, `Day`, `Hour`, `Minute`, `Significant Wave Height`, `Energy Period`.
- Rows 4+: Hourly or sub-hourly data values:
- `Significant Wave Height` in meters [m].
- `Energy Period` in seconds [s].

## Configuration

The wave resource is declared in `plant_config.yaml` under the site resources:

```yaml
sites:
site:
resources:
wave_resource:
resource_model: WaveResource
resource_parameters:
resource_dir: resource_files/wave/
resource_filename: wave_lat43.81_lon-124.82__2010.csv
resource_year: 2010
```

The `resource_year` parameter is used to generate the hourly timestamp arrays (year, month, day, hour, minute) that are passed internally to the PySAM MhkWave model in timeseries mode.

The wave resource outputs are connected to the wave performance model via `resource_to_tech_connections` in `plant_config.yaml`:

```yaml
resource_to_tech_connections:
- [site.wave_resource, wave, significant_wave_height]
- [site.wave_resource, wave, energy_period]
```
57 changes: 57 additions & 0 deletions docs/technology_models/wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
(wave_performance)=
# Wave Energy Models

## PySAM Wave Performance Model

The **PySAM Wave Performance Model** simulates electricity generation from **wave energy converter (WEC) devices** using a timeseries wave resource. The model wraps the [PySAM MhkWave module](https://nrel-pysam.readthedocs.io/en/main/modules/MhkWave.html) implementation of the wave energy performance model used in the [System Advisor Model (SAM)](https://sam.nlr.gov/).

This component integrates the PySAM **MhkWave** module into an H2I performance model. To use this model, specify `"PySAMWavePerformanceModel"` as the performance model.

The model converts a wave resource timeseries (significant wave height and energy period) and a device power matrix into:
- timeseries electricity generation
- total energy production over the simulation period
- annualized energy production
- system capacity factor

### Model Overview

The model represents an array of wave energy converters operating in an ocean wave resource. Electricity production is calculated at each timestep by looking up device power output in the wave power matrix using the instantaneous significant wave height (Hs) and energy period (Te), then scaling by the number of devices.

The model operates in timeseries mode (`wave_resource_model_choice = 1`) and requires hourly Hs and Te arrays. Use the {ref}`wave_resource` component to read and interpolate wave data files to the required hourly resolution.

(pysam-options-wave)=
#### PySAM Options

A user can specify any of the attributes available within the [MhkWave module](https://nrel-pysam.readthedocs.io/en/main/modules/MhkWave.html) using the `pysam_options` dictionary. The top-level keys correspond to the variable groups in the MhkWave module.

The most common use is to override the default loss parameters:

```yaml
pysam_options:
MHKWave:
loss_array_spacing: 0.0 # array-spacing loss [%]
loss_resource_overprediction: 0.0 # resource overprediction loss [%]
loss_transmission: 2.0 # transmission loss [%]
loss_downtime: 5.0 # availability loss [%]
loss_additional: 0.0 # additional loss [%]
```

By default all losses are set to zero. Override via `pysam_options` to model realistic system availability.

#### Wave Power Matrix

The `wave_power_matrix` is a 2-D lookup table of device power output [kW] as a function of significant wave height Hs [m] and energy period Te [s]. It must be provided as a list of rows:

- Row 0: Te bin centers [s] (header row; first element is 0.0)
- Rows 1+: Each row starts with the Hs bin center [m], followed by the device power output [kW] at each Te bin

Example (3-row excerpt):

```yaml
wave_power_matrix:
- [0.0, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5]
- [0.25, 0.0, 0.0, 0.0, 0.0, 0.4, 0.6, 0.8, 1.0, 1.1, 1.1]
- [0.75, 0.0, 0.0, 0.0, 0.0, 3.2, 5.3, 7.4, 9.1, 9.8, 9.5]
```

The power matrix format follows the SAM convention and can be exported from SAM for any supported reference model.
7 changes: 6 additions & 1 deletion docs/user_guide/model_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ auto-generated API page.
- other components:
+ {py:class}`~h2integrate.resource.tidal.TidalResource` - A resource component for processing tidal data from a CSV file.

- `wave`
- other components:
+ {py:class}`~h2integrate.resource.wave.WaveResource` - A resource component for processing wave data from a CSV file.

- `wind`: wind resource data providers
- other components:
+ {py:class}`~h2integrate.resource.wind.openmeteo_wind.OpenMeteoHistoricalWindResource`
Expand Down Expand Up @@ -230,9 +234,10 @@ auto-generated API page.
- combined cost and financial models:
+ {py:class}`~h2integrate.converters.steel.steel.SteelCostAndFinancialModel` - An OpenMDAO component for calculating the costs associated with steel production.

- `water_power`: tidal and run-of-river hydropower
- `water_power`: wave, tidal, and run-of-river hydropower

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes glad we are oxford comma people here

- performance models:
+ {py:class}`~h2integrate.converters.water_power.tidal_pysam.PySAMTidalPerformanceModel` - An OpenMDAO component that wraps the PySAM MhkTidal model.
+ {py:class}`~h2integrate.converters.water_power.wave_pysam.PySAMWavePerformanceModel` - An OpenMDAO component that wraps the PySAM MhkWave model.
+ {py:class}`~h2integrate.converters.water_power.hydro_plant_run_of_river.RunOfRiverHydroPerformanceModel` - An OpenMDAO component for modeling the performance of a run-of-river hydropower plant.
- cost models:
+ {py:class}`~h2integrate.converters.water_power.pysam_marine_cost.PySAMMarineCostModel` - An OpenMDAO component for calculating the costs associated with Marine Hydrokinetic (MHK) energy systems.
Expand Down
1 change: 0 additions & 1 deletion examples/05_wind_h2_opt/run_wind_electrolyzer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from h2integrate import H2IntegrateModel


# Create a GreenHEART model
h2i = H2IntegrateModel("wind_plant_electrolyzer.yaml")

# Run the model
Expand Down
1 change: 0 additions & 1 deletion examples/06_custom_tech/run_wind_paper.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from h2integrate import H2IntegrateModel


# Create a GreenHEART model
h2i = H2IntegrateModel("wind_plant_paper.yaml")

# Run the model
Expand Down
17 changes: 13 additions & 4 deletions examples/09_co2/direct_ocean_capture/plant_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ sites:
resource_model: WTKNLRDeveloperAPIWindResource
resource_parameters:
resource_year: 2010
wave_resource:
resource_model: WaveResource
resource_parameters:
resource_dir: resource_files/wave/
resource_filename: wave_lat43.81_lon-124.82__2010.csv
resource_year: 2010
# array of arrays containing left-to-right technology
# interconnections; can support bidirectional connections
# with the reverse definition.
# this will naturally grow as we mature the interconnected tech
technology_interconnections:
- [hopp, combiner, electricity, cable]
- [wave, combiner, electricity, cable]
- [wind, combiner, electricity, cable]
- [combiner, battery, electricity, cable]
# combine the battery output with the wind and hopp generation
# combine the battery output with the wind and wave generation
- [battery, elec_combiner, electricity, cable]
- [combiner, elec_combiner, electricity, cable]
# connect the electricity supply to the doc
Expand All @@ -29,6 +35,9 @@ tech_to_dispatch_connections:
resource_to_tech_connections:
# connect the wind resource to the wind technology
- [site.wind_resource, wind, wind_resource_data]
# connect the wave resource to the wave technology
- [site.wave_resource, wave, significant_wave_height]
- [site.wave_resource, wave, energy_period]
plant:
plant_life: 30
finance_parameters:
Expand Down Expand Up @@ -61,8 +70,8 @@ finance_parameters:
electricity:
commodity: electricity
commodity_stream: combiner
technologies: [hopp, wind, battery]
technologies: [wave, wind, battery]
co2:
commodity: co2
commodity_stream: doc
technologies: [hopp, wind, battery, doc]
technologies: [wave, wind, battery, doc]
1 change: 0 additions & 1 deletion examples/09_co2/direct_ocean_capture/run_wind_wave_doc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from h2integrate import H2IntegrateModel


# Create a GreenHEART model
h2i_model = H2IntegrateModel("offshore_plant_doc.yaml")

# Set battery demand profile
Expand Down
63 changes: 56 additions & 7 deletions examples/09_co2/direct_ocean_capture/tech_config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,68 @@
name: technology_config
description: This plant has offshore wind and wave energy connected to a direct ocean capture device
technologies:
hopp:
wave:
performance_model:
model: HOPPComponent
model: PySAMWavePerformanceModel
cost_model:
model: HOPPComponent
model: PySAMMarineCostModel
dispatch_rule_set:
model: PyomoDispatchGenericConverter
model_inputs:
shared_parameters:
device_rating_kw: 286 # kW, rated power of a single wave device
num_devices: 108 # number of wave energy converters
performance_parameters:
cache_dir: cache
enable_caching: true
hopp_config: !include tech_inputs/hopp_config.yaml
cost_year: 2022
resource_year: 2010
wave_power_matrix:
- [0.0, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5, 10.5, 11.5, 12.5, 13.5, 14.5, 15.5, 16.5, 17.5, 18.5,
19.5, 20.5]
- [0.25, 0.0, 0.0, 0.0, 0.0, 0.4, 0.6, 0.8, 1.0, 1.1, 1.1, 1.0, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.3, 0.2, 0.2, 0.0]
- [0.75, 0.0, 0.0, 0.0, 0.0, 3.2, 5.3, 7.4, 9.1, 9.8, 9.5, 8.6, 7.4, 6.2, 5.1, 4.1, 3.4, 2.8, 2.3, 1.9, 1.6, 0.0]
- [1.25, 0.0, 0.0, 0.0, 0.0, 9.0, 14.8, 20.5, 25.0, 26.8, 25.9, 23.3, 20.0, 16.8, 13.8, 11.3, 9.2, 7.6, 6.3, 5.2,
4.3, 0.0]
- [1.75, 0.0, 0.0, 0.0, 0.0, 17.6, 28.9, 39.9, 48.3, 51.6, 49.7, 44.7, 38.4, 32.2, 26.5, 21.7, 17.8, 14.6, 12.1,
10.0, 8.4, 0.0]
- [2.25, 0.0, 0.0, 0.0, 0.0, 29.0, 47.5, 65.4, 78.8, 83.8, 80.6, 72.4, 62.3, 52.2, 43.0, 35.3, 28.9, 23.8, 19.7,
16.3, 13.7, 0.0]
- [2.75, 0.0, 0.0, 0.0, 0.0, 43.2, 70.7, 97.0, 116.3, 123.1, 118.1, 106.1, 91.3, 76.5, 63.2, 51.9, 42.5, 35.0, 28.9,
24.1, 20.1, 0.0]
- [3.25, 0.0, 0.0, 0.0, 0.0, 60.2, 98.3, 134.5, 160.5, 169.3, 162.1, 145.5, 125.2, 105.0, 86.8, 71.3, 58.5, 48.2,
39.9, 33.2, 27.8, 0.0]
- [3.75, 0.0, 0.0, 0.0, 0.0, 79.9, 130.4, 177.8, 211.2, 222.0, 212.2, 190.4, 164.0, 137.6, 113.8, 93.6, 76.9, 63.3,
52.5, 43.7, 36.6, 0.0]
- [4.25, 0.0, 0.0, 0.0, 0.0, 102.4, 166.7, 226.7, 268.3, 281.1, 268.2, 240.5, 207.2, 174.1, 144.1, 118.5, 97.4,
80.3, 66.6, 55.5, 46.5, 0.0]
- [4.75, 0.0, 0.0, 0.0, 0.0, 127.6, 207.4, 281.2, 286.0, 286.0, 286.0, 286.0, 255.0, 214.3, 177.5, 146.1, 120.2,
99.2, 82.2, 68.6, 57.6, 0.0]
- [5.25, 0.0, 0.0, 0.0, 0.0, 155.4, 252.4, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 258.2, 214.0, 176.3, 145.1,
119.8, 99.4, 83.0, 69.7, 0.0]
- [5.75, 0.0, 0.0, 0.0, 0.0, 186.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 253.6, 209.0, 172.2,
142.2, 118.1, 98.6, 82.8, 0.0]
- [6.25, 0.0, 0.0, 0.0, 0.0, 219.2, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 244.2, 201.2,
166.4, 138.2, 115.5, 97.1, 0.0]
- [6.75, 0.0, 0.0, 0.0, 0.0, 255.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 281.9, 232.4,
192.2, 159.7, 133.5, 112.3, 0.0]
- [7.25, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 265.6,
219.8, 182.8, 152.9, 128.7, 0.0]
- [7.75, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0,
249.0, 207.2, 173.4, 146.0, 0.0]
- [8.25, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0,
279.9, 233.0, 195.1, 164.4, 0.0]
- [8.75, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0,
286.0, 260.2, 218.0, 183.8, 0.0]
- [9.25, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0,
286.0, 286.0, 242.1, 204.1, 0.0]
- [9.75, 0.0, 0.0, 0.0, 0.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0, 286.0,
286.0, 286.0, 267.4, 225.6, 0.0]
cost_parameters:
reference_model_number: 3 # RM3: Wave Point Absorber
water_depth: 482 # meters
distance_to_shore: 50 # km
number_rows: 18
device_spacing: 600 # meters
row_spacing: 600 # meters
cable_system_overbuild: 20 # percent
dispatch_rule_parameters:
commodity: electricity
commodity_rate_units: kW
Expand Down

This file was deleted.

Loading
Loading