Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
070285e
added draft storage model baseclass
elenya-grant Mar 23, 2026
a8535f4
Merge branch 'develop' of github.com:NREL/H2Integrate into dispatch/s…
elenya-grant Mar 25, 2026
f94088c
updated draft storage baseclass
elenya-grant Mar 25, 2026
a48164e
Merge remote-tracking branch 'h2i_upstream/develop' into dispatch/sto…
elenya-grant Mar 25, 2026
c0a3b87
added docstring to run_storage method
elenya-grant Mar 25, 2026
8e7c514
minor updates to comments in storage_model_baseclass
elenya-grant Mar 26, 2026
7dbe7da
Merge remote-tracking branch 'h2i_upstream/develop' into dispatch/sto…
elenya-grant Mar 27, 2026
3aaca71
updated storage performance model to inherit baseclass
elenya-grant Mar 27, 2026
27c1bdb
fixed storage performance model and storage baseclass
elenya-grant Mar 27, 2026
f7cebbc
updated storage autosizing model
elenya-grant Mar 27, 2026
17e241d
updated pysam battery to use baseclass and removed battery_baseclass
elenya-grant Mar 27, 2026
1029930
removed commented out code and simplified some docstrings
elenya-grant Mar 27, 2026
78b3000
removed unnecessary docstrings
elenya-grant Mar 30, 2026
fce6042
updated changelog
elenya-grant Mar 30, 2026
2775a4a
merged changelog
elenya-grant Mar 31, 2026
1596261
PR review: minor personal preferences
johnjasa Mar 31, 2026
465fa8d
Merge branch 'dispatch/storage_model_baseclass' of https://github.com…
johnjasa Mar 31, 2026
57e5f60
updated inline comment
elenya-grant Mar 31, 2026
b9ec846
updated inline comment
elenya-grant Mar 31, 2026
b71cd5e
Merge branch 'develop' into dispatch/storage_model_baseclass
johnjasa Mar 31, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- Updated the `StorageAutoSizingModel` model to be compatible with Pyomo control strategies [PR 621](https://github.com/NatLabRockies/H2Integrate/pull/621)
- Removed a few usages of `shape_by_conn` due to issues with OpenMDAO v3.43.0 release on some computers [PR 632](https://github.com/NatLabRockies/H2Integrate/pull/632)
- Made generating an XDSM diagram from connections in a model optional and added documentation on model visualization. [PR 629](https://github.com/NatLabRockies/H2Integrate/pull/629)
- Added a storage performance baseclass model `StoragePerformanceBase` and updated the other storage performance models to inherit it [PR 624](https://github.com/NatLabRockies/H2Integrate/pull/624)

## 0.7.1 [March 13, 2026]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,6 @@ def __attrs_post_init__(self):
] * self.n_control_window


def dummy_function():
"""Dummy function used for setting OpenMDAO input/output defaults but otherwise unused.

Returns:
None: empty output
"""
return None


class PyomoControllerBaseClass(om.ExplicitComponent):
def initialize(self):
"""
Expand Down Expand Up @@ -125,7 +116,7 @@ def setup(self):
# create output for the pyomo control model
self.add_discrete_output(
"pyomo_dispatch_solver",
val=dummy_function,
val=lambda: None,
desc="callable: fully formed pyomo model and execution logic to be run \
by owning technologies performance model",
)
Expand Down
8 changes: 4 additions & 4 deletions h2integrate/control/test/test_heuristic_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ def test_heuristic_load_following_battery_dispatch(
with subtests.test("Check battery_electricity"):
assert (
pytest.approx(expected_battery_electricity)
== prob.get_val("battery.battery_electricity_out", units="kW")[0:24]
== prob.get_val("battery.storage_electricity_out", units="kW")[0:24]
)

with subtests.test("Check SOC"):
Expand Down Expand Up @@ -424,7 +424,7 @@ def test_heuristic_load_following_battery_dispatch(
with subtests.test("Check battery_electricity for min SOC"):
assert (
pytest.approx(expected_battery_electricity)
== prob.get_val("battery.battery_electricity_out", units="kW")[:5]
== prob.get_val("battery.storage_electricity_out", units="kW")[:5]
)

with subtests.test("Check SOC for min SOC"):
Expand Down Expand Up @@ -488,7 +488,7 @@ def test_heuristic_load_following_battery_dispatch(
with subtests.test("Check battery_electricity for max SOC"):
assert (
pytest.approx(expected_battery_electricity, abs=abs_tol, rel=rel_tol)
== prob.get_val("battery.battery_electricity_out", units="kW")[:5]
== prob.get_val("battery.storage_electricity_out", units="kW")[:5]
)

with subtests.test("Check SOC for max SOC"):
Expand Down Expand Up @@ -747,7 +747,7 @@ def test_heuristic_load_following_battery_dispatch_change_capacities(
with subtests.test("Check battery_electricity"):
assert (
pytest.approx(expected_battery_electricity)
== prob.get_val("battery.battery_electricity_out", units="kW")[0:24]
== prob.get_val("battery.storage_electricity_out", units="kW")[0:24]
)

with subtests.test("Check SOC"):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,13 @@ def test_battery_openloop(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -381,13 +381,13 @@ def test_battery_pyo(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -508,13 +508,13 @@ def test_both_pyomo_controllers(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -586,13 +586,13 @@ def test_both_openloop_controllers(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -668,13 +668,13 @@ def test_h2s_pyomo_battery_openloop(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -765,13 +765,13 @@ def test_battery_pyomo_h2s_openloop(subtests, plant_config):

with subtests.test("Battery: Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[:24],
bat_expected_charge,
rtol=1e-6,
)
with subtests.test("Battery: Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[:24],
prob.get_val("battery.storage_electricity_discharge", units="kW")[:24],
bat_expected_discharge,
rtol=1e-6,
)
Expand Down
8 changes: 4 additions & 4 deletions h2integrate/control/test/test_openloop_storage_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ def test_pysam_battery_with_demand_openloop(plant_config, storage_perf_params, s
)
with subtests.test("Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW"),
prob.get_val("battery.storage_electricity_discharge", units="kW"),
expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -298,7 +298,7 @@ def test_pysam_battery_with_demand_openloop(plant_config, storage_perf_params, s
)
with subtests.test("Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW"),
prob.get_val("battery.storage_electricity_charge", units="kW"),
expected_charge,
rtol=1e-6,
)
Expand Down Expand Up @@ -380,7 +380,7 @@ def test_pysam_battery_with_simple_openloop(plant_config, storage_perf_params, s
)
with subtests.test("Expected discharge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW"),
prob.get_val("battery.storage_electricity_discharge", units="kW"),
expected_discharge,
rtol=1e-6,
)
Expand Down Expand Up @@ -415,7 +415,7 @@ def test_pysam_battery_with_simple_openloop(plant_config, storage_perf_params, s
)
with subtests.test("Expected charge"):
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW"),
prob.get_val("battery.storage_electricity_charge", units="kW"),
expected_charge,
rtol=1e-6,
)
Expand Down
36 changes: 18 additions & 18 deletions h2integrate/control/test/test_optimal_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,16 @@ def test_min_operating_cost_load_following_battery_dispatch(

# Test that discharge is always positive
with subtests.test("Discharge is always positive"):
assert np.all(prob.get_val("battery.battery_electricity_discharge") >= 0)
assert np.all(prob.get_val("battery.storage_electricity_discharge") >= 0)
with subtests.test("Charge is always negative"):
assert np.all(prob.get_val("battery.battery_electricity_charge") <= 0)
assert np.all(prob.get_val("battery.storage_electricity_charge") <= 0)
# Set rtol lower b/c the values are in kW
with subtests.test("Charge + Discharge == battery_electricity_out"):
charge_plus_discharge = prob.get_val("battery.battery_electricity_charge") + prob.get_val(
"battery.battery_electricity_discharge"
charge_plus_discharge = prob.get_val("battery.storage_electricity_charge") + prob.get_val(
"battery.storage_electricity_discharge"
)
np.testing.assert_allclose(
charge_plus_discharge, prob.get_val("battery_electricity_out"), rtol=1e-2
charge_plus_discharge, prob.get_val("storage_electricity_out"), rtol=1e-2
)
with subtests.test("Initial SOC is correct"):
assert pytest.approx(prob.model.get_val("battery.SOC")[0], rel=1e-2) == 50
Expand All @@ -255,25 +255,25 @@ def test_min_operating_cost_load_following_battery_dispatch(

with subtests.test("SOC increases when charging"):
assert np.all(
prob.get_val("battery.battery_electricity_charge", units="kW")[indx_soc_increase] <= 0
prob.get_val("battery.storage_electricity_charge", units="kW")[indx_soc_increase] <= 0
)
assert np.all(
prob.get_val("battery.battery_electricity_charge", units="kW")[indx_soc_decrease] == 0
prob.get_val("battery.storage_electricity_charge", units="kW")[indx_soc_decrease] == 0
)
assert np.all(
prob.get_val("battery.battery_electricity_charge", units="kW")[indx_soc_same] == 0
prob.get_val("battery.storage_electricity_charge", units="kW")[indx_soc_same] == 0
)

with subtests.test("SOC decreases when discharging"):
assert np.all(
prob.get_val("battery.battery_electricity_discharge", units="kW")[indx_soc_decrease] > 0
prob.get_val("battery.storage_electricity_discharge", units="kW")[indx_soc_decrease] > 0
)
assert np.all(
prob.get_val("battery.battery_electricity_discharge", units="kW")[indx_soc_increase]
prob.get_val("battery.storage_electricity_discharge", units="kW")[indx_soc_increase]
== 0
)
assert np.all(
prob.get_val("battery.battery_electricity_discharge", units="kW")[indx_soc_same] == 0
prob.get_val("battery.storage_electricity_discharge", units="kW")[indx_soc_same] == 0
)

with subtests.test("Max SOC <= Max storage percent"):
Expand All @@ -284,28 +284,28 @@ def test_min_operating_cost_load_following_battery_dispatch(

with subtests.test("Charge never exceeds charge rate"):
assert (
prob.get_val("battery.battery_electricity_charge", units="kW").min() >= -1 * charge_rate
prob.get_val("battery.storage_electricity_charge", units="kW").min() >= -1 * charge_rate
)

with subtests.test("Discharge never exceeds discharge rate"):
assert (
prob.get_val("battery.battery_electricity_discharge", units="kW").max()
prob.get_val("battery.storage_electricity_discharge", units="kW").max()
<= discharge_rate
)

with subtests.test("Discharge never exceeds demand"):
assert np.all(
prob.get_val("battery.battery_electricity_discharge", units="kW").max() <= demand_in
prob.get_val("battery.storage_electricity_discharge", units="kW").max() <= demand_in
)

with subtests.test("Sometimes discharges"):
assert any(
k > 1e-3 for k in prob.get_val("battery.battery_electricity_discharge", units="kW")
k > 1e-3 for k in prob.get_val("battery.storage_electricity_discharge", units="kW")
)

with subtests.test("Sometimes charges"):
assert any(
k < -1e-3 for k in prob.get_val("battery.battery_electricity_charge", units="kW")
k < -1e-3 for k in prob.get_val("battery.storage_electricity_charge", units="kW")
)

with subtests.test("Cumulative charge/discharge does not exceed storage capacity"):
Expand All @@ -315,15 +315,15 @@ def test_min_operating_cost_load_following_battery_dispatch(
with subtests.test("Expected discharge from hour 10-30"):
expected_discharge = np.concat([np.zeros(8), np.ones(8) * 5000, np.zeros(4)])
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_discharge", units="kW")[0:20],
prob.get_val("battery.storage_electricity_discharge", units="kW")[0:20],
expected_discharge,
rtol=1e-2,
)

with subtests.test("Expected charge hour 0-24"):
expected_charge = -1 * np.concat([np.zeros(16), np.ones(8) * 4000])
np.testing.assert_allclose(
prob.get_val("battery.battery_electricity_charge", units="kW")[0:24],
prob.get_val("battery.storage_electricity_charge", units="kW")[0:24],
expected_charge,
rtol=1e-2,
)
Expand Down
45 changes: 0 additions & 45 deletions h2integrate/storage/battery/battery_baseclass.py

This file was deleted.

Loading
Loading