Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
5d1fd35
working on ard integration
jaredthomas68 Aug 5, 2025
bb38a07
wip ard integration
jaredthomas68 Aug 5, 2025
7a50791
complete merge
jaredthomas68 Aug 7, 2025
cf6f99c
fix syntax
jaredthomas68 Aug 7, 2025
70b9cbc
wip: ard integration needs full year wind data
jaredthomas68 Aug 8, 2025
7e807b9
add wind resource with api capability
jaredthomas68 Aug 8, 2025
3383d99
Merge branch 'develop' into ard
jaredthomas68 Aug 8, 2025
c499c7f
update type for resource_config option
jaredthomas68 Aug 8, 2025
1af4bdf
move ard tests into a new subfolder
jaredthomas68 Aug 8, 2025
1402a47
wip ard integration stuck at needing time-series
jaredthomas68 Aug 9, 2025
95b311c
add test for ard
jaredthomas68 Aug 9, 2025
92744e7
wip debuggin ard integration
jaredthomas68 Aug 11, 2025
284291c
update ard example for some refactor
jaredthomas68 Aug 25, 2025
a0834cf
add resource request
jaredthomas68 Aug 26, 2025
69fb21c
inputs for example
jaredthomas68 Aug 26, 2025
9c0c415
complete merge
jaredthomas68 Sep 10, 2025
e31e296
resolve merge conflicts
jaredthomas68 Oct 3, 2025
4f01420
remove jared's attempt at wind resource integration
jaredthomas68 Oct 3, 2025
4bf6bb2
wip: add ard example
jaredthomas68 Oct 5, 2025
9bf8ff2
get ard example working
jaredthomas68 Oct 6, 2025
2f3dd3e
wip: debugging tests
jaredthomas68 Oct 7, 2025
80cf490
merge from develop
jaredthomas68 Oct 11, 2025
6def61c
update docs and changelog
jaredthomas68 Oct 13, 2025
3be97e1
include ard in pyproject.toml dependencies
jaredthomas68 Oct 13, 2025
f8f0ae7
include ard in tech overview
jaredthomas68 Oct 15, 2025
f503605
backmerge from develop
jaredthomas68 Oct 22, 2025
b7d4934
install ard from PyPI
jaredthomas68 Oct 22, 2025
0a122f1
remove duplicate test. update docs
jaredthomas68 Oct 22, 2025
9f1fb67
Merge branch 'develop' into ard
johnjasa Oct 26, 2025
67d1842
finish merge
jaredthomas68 Oct 27, 2025
0254d0a
update naming in ard example
jaredthomas68 Oct 27, 2025
bc5dfac
resolve merge conflicts
jaredthomas68 Oct 27, 2025
cb27a1d
Merge branch 'develop' into ard
jaredthomas68 Oct 27, 2025
fd6247c
Merge branch 'develop' into ard
johnjasa Nov 3, 2025
46696b7
resolve merge conflicts and renaming corrections
jaredthomas68 Nov 3, 2025
f1d5b7d
Minor docstring and Ard edits
johnjasa Nov 4, 2025
ae42667
Merge branch 'develop' into ard
kbrunik Nov 5, 2025
c42c48a
Merge branch 'develop' into ard
johnjasa Nov 6, 2025
ea68c23
backmerge develop
jaredthomas68 Nov 10, 2025
572b99e
wip: converting to use h2i resource management for wind
jaredthomas68 Nov 13, 2025
3382e0e
finish merge
jaredthomas68 Nov 13, 2025
5c299f8
Merge branch 'develop' into ard
kbrunik Nov 20, 2025
9b6ce3b
working through pre-commit
johnjasa Nov 20, 2025
7dd8472
Merge branch 'develop' into ard
johnjasa Nov 20, 2025
8ef1120
apple silicon install instructions wip
jaredthomas68 Dec 3, 2025
d88502a
resolve conflicts
jaredthomas68 Dec 3, 2025
bd41ad9
fix merge conflicts
jaredthomas68 Jan 28, 2026
80fed27
update ard barnch to work with new develop branch
jaredthomas68 Jan 28, 2026
d6b3221
cleaning up
jaredthomas68 Jan 29, 2026
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 CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Changelog

## 0.5.x [TBD]

- Updates models for NumPy version 2.4.0
- Update test values for WOMBAT update to 0.13.0
- Added standalone iron DRI and steel EAF performance and cost models
Expand Down Expand Up @@ -29,6 +28,7 @@
- Remove unused dependencies.
- Fixes typos for skipped folders.
- Fixes missing dependencies for `gis` modifier used in new iron mapping tests.
- Added Ard as a combined performance and cost model

## 0.5.1 [December 18, 2025]

Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,11 @@ pip install h2integrate

3. Create a conda environment and install H2Integrate and all its dependencies

- for apple silicon
```bash
conda env create -f environment.yml
conda CONDA_SUBDIR=osx-arm64 conda env create -f environment.yml
conda activate h2i-ard
conda env config vars set CONDA_SUBDIR=osx-arm64 # this command makes the environment permanently native
```

4. Install Cbc.
Expand Down
1 change: 1 addition & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ parts:
- file: technology_models/methanol.md
- file: technology_models/ammonia.md
- file: technology_models/pysam_battery.md
- file: technology_models/wind_plant_ard.md
- file: technology_models/geologic_hydrogen.md
- file: technology_models/grid
- file: technology_models/hydrogen_storage.md
Expand Down
34 changes: 34 additions & 0 deletions docs/technology_models/wind_plant_ard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Wind Plant - Ard

The intent of [Ard](https://github.com/WISDEM/Ard) is to be a modular, full-stack multi-disciplinary optimization tool for wind farms. By incorporating Ard in H2Integrate, we are able to draw on many wind technology models developed at NREL and other institutions without managing them or their connections in Ard. Models connected in Ard include many parts of [WISDEM](https://github.com/WISDEM/WISDEM), [FLORIS](https://github.com/NREL/floris), and [OptiWindNet](https://github.com/DTUWindEnergy/OptiWindNet). Ard also provides constraint functions and wind farm layout generation capabilities among other things. Because Ard has been developed in a modular way, you may extend Ard fairly easily to include other wind models of interest.

Ard is included in H2Integrate as an [OpenMDAO sub-model](https://openmdao.org/newdocs/versions/latest/features/building_blocks/components/submodel_comp.html), which means that Ard is treated as a distinct and separate OpenMDAO system within the larger H2I OpenMDAO system. In this way, the user can run an independent wind farm optimization within Ard, or allow H2Integrate to manage the wind farm design variables directly. The drawback of including Ard as a sub-model is that N2 diagrams made from the H2Integrate problems will show Ard only as a single black-box model, rather than showing all the subsystems within Ard. If you wish to view an N2 diagram of Ard, you will need to use the Ard problem instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be possible to show how a user would create an Ard problem instead of just the H2Integrate problem?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I referenced the Ard docs where the user can find that information if desired, and I also added the command to show how to view the N2 of the Ard sub problem within an H2Integrate model.

## Some Key Capabilities of Ard
- Highly modular to include alternate/new models and capabilities
- Built using OpenMDAO
- Wind farm layout optimization
- Turbine locations
- Ordered grid layouts
- Continuous locations layouts
- Boundaries
- Single boundary
- Multiple discrete boundary regions
- Arbitrary polygonal boundaries shapes
- Collection cable array optimization
- OptiWindNet
- Radial configurations
- Branched configurations
- Aerodynamics
- FLORIS
- Cost and finance
- WISDEM
- LandBOSSE
- ORBIT
- FinanceSE

## Wind Resource
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you specify what wind resource data is needed by ard and what the units should be? like that and needs wind speeds in m/s or whatever? Cause if folks are downloading resource data from the openmeteo web API - they may have wind speed in km/h (that's the default unit)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done, and I added a link to the WindIO docs that define the resource input for Ard.

The wind resource capabilities of H2Integrate are not yet connected with Ard, so the user must provide a wind resource file directly to the Ard model inputs.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this because of how the wind resource needs to be formatted? If yes, could you explain the necessary format of the file and what the attributes--or column--requirements are)?

Copy link
Collaborator

Choose a reason for hiding this comment

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

it looks like you're using openmeteo, is this something that you're integrating @elenya-grant?

Copy link
Collaborator

Choose a reason for hiding this comment

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

yes - PR #332

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have not connected Ard to the wind resource capabilities in H2I because it would require passing weather data at run time, but Ard requires the weather data at setup time.


## Examples
For an example of using Ard in an H2Integrate model, see `examples/xx_wind_ard`. Note that Ard uses a combination of input files, including a [wind IO](https://github.com/IEAWindSystems/windIO) file.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you add a list of the necessary input files for ARD, with maybe a one sentence description about them?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed, and pointing to the Ard docs where possible here would be quite helpful!

Copy link
Collaborator

Choose a reason for hiding this comment

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

If this example is really similar to 01_onshore in the Ard documentation you could consider linking it for additional explanation about what's happening: https://wisdem.github.io/Ard/examples/01_onshore/optimization_demo.html

2 changes: 2 additions & 0 deletions docs/user_guide/model_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ Below summarizes the available performance, cost, and financial models for each
+ `'floris_wind_plant_performance'`
- cost models:
+ `'atb_wind_cost'`
- combined models:
+ `'wind_plant_ard'`
- `solar`: solar-PV panels
- performance models:
+ `'pysam_solar_plant_performance'`
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: h2integrate
name: h2i-ard
channels:
- conda-forge
- defaults
Expand Down
72 changes: 72 additions & 0 deletions examples/test/test_all_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,78 @@ def test_simple_dispatch_example(subtests):
assert pytest.approx(electricity_lcoe, rel=1e-6) == 78.01723


def test_windard_pv_battery_dispatch_example(subtests):
# Change the current working directory to the example's directory
os.chdir(EXAMPLE_DIR / "xx_wind_ard")

# Create the model
model = H2IntegrateModel("./h2i_inputs/wind_pv_battery.yaml")

# Run the model
model.run()

# Post-process the results
model.post_process()

with subtests.test("Check wind generation"):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a reason to not set the generation to a value? It seems like it might be easier to check in the future if this test breaks if we have a better idea of the value.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with Kaitlin - I think that having subtests on the value of the total wind generation profile and total solar generation profile would be a good so if other subtests fail (like LCOE or total electricity dispatched, etc), it will be easier to identify what causes other subtest failures.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good point. I think this was a holdover from just getting it to work. Thanks for calling it out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Now testing total gen of each tech against saved values

# Wind should generate some electricity
wind_electricity = model.prob.get_val("wind.electricity_out", units="MW")
assert wind_electricity.sum() > 0

with subtests.test("Check solar generation"):
# Solar should generate some electricity
solar_electricity = model.prob.get_val("solar.electricity_out", units="MW")
assert solar_electricity.sum() > 0

with subtests.test("Check battery gets wind and solar output"):
# Wind plus solar electricity should match battery input (direct connection)
battery_electricity_in = model.prob.get_val("battery.electricity_in", units="MW")
assert wind_electricity.sum() + solar_electricity.sum() == pytest.approx(
battery_electricity_in.sum(), rel=1e-6
)

with subtests.test("Check demand satisfaction"):
dispatched_electricity = model.prob.get_val("battery.electricity_out", units="MW")
# Demand should be met for the last part of the year
assert np.allclose(
dispatched_electricity[8700:],
model.prob.get_val("battery.electricity_demand", units="MW")[8700:],
)

# Subtest for LCOE
with subtests.test("Check dispatched LCOE value"):
lcoe = model.prob.get_val("finance_subgroup_dispatched_electricity.LCOE")[0]
assert pytest.approx(lcoe, rel=1e-6) == 0.22171693744337054

with subtests.test("Check generation LCOE value (excludes battery)"):
lcoe = model.prob.get_val("finance_subgroup_produced_electricity.LCOE")[0]
assert pytest.approx(lcoe, rel=1e-6) == 0.06770722531229562

# Subtest for total electricity produced
with subtests.test("Check total electricity dispatched"):
total_electricity = model.prob.get_val(
"finance_subgroup_dispatched_electricity.electricity_sum.total_electricity_produced",
units="MW*h/year",
).sum()
assert total_electricity == pytest.approx(dispatched_electricity.sum())

# Subtest for electricity curtailed
with subtests.test("Check electricity curtailed"):
electricity_curtailed = model.prob.get_val(
"battery.electricity_unused_commodity", units="MW"
).sum()

# import pdb; pdb.set_trace()
assert electricity_curtailed == pytest.approx(525088.2729268058, rel=1e-6)

# Subtest for missed load
with subtests.test("Check electricity missed load"):
electricity_missed_load = np.linalg.norm(
model.prob.get_val("battery.electricity_unmet_demand", units="MW")
)
assert electricity_missed_load == pytest.approx(468.28057304873026)


def test_csvgen_design_of_experiments(subtests):
os.chdir(EXAMPLE_DIR / "20_solar_electrolyzer_doe")

Expand Down
Loading
Loading