From 0abe06fa083a9ebc6fd96ea0ec57aa2f07a7baa6 Mon Sep 17 00:00:00 2001 From: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Date: Thu, 9 Apr 2026 12:50:50 -0600 Subject: [PATCH 1/4] added test to highlight error --- .../test/test_storage_performance_model.py | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/h2integrate/storage/test/test_storage_performance_model.py b/h2integrate/storage/test/test_storage_performance_model.py index 159ee36cf..6edcbd235 100644 --- a/h2integrate/storage/test/test_storage_performance_model.py +++ b/h2integrate/storage/test/test_storage_performance_model.py @@ -957,3 +957,136 @@ def test_generic_storage_with_simple_control_with_losses_round_trip(plant_config expected_charge, rtol=1e-6, ) + + +@pytest.mark.regression +@pytest.mark.parametrize("n_timesteps", [24]) +def test_generic_storage_charge_more_than_available(plant_config, subtests): + # this tests a case where the demand < charge rate and charge_rate=discharge_rate + model_inputs = { + "shared_parameters": { + "commodity": "hydrogen", + "commodity_rate_units": "kg/h", + }, + "performance_parameters": { + "max_capacity": 40, + "max_charge_rate": 10, + "min_soc_fraction": 0.1, + "max_soc_fraction": 1.0, + "init_soc_fraction": 0.1, + "commodity_amount_units": "kg", + "charge_equals_discharge": True, + "charge_efficiency": 1.0, + "discharge_efficiency": 1.0, + "demand_profile": 0.0, + }, + "control_parameters": {"set_demand_as_avg_commodity_in": False}, + } + + prob = om.Problem() + + commodity_demand = np.full(24, 5.0) + commodity_in = np.concat([np.zeros(3), np.cumsum(np.ones(15)), np.full(6, 4.0)]) + nominal_set_point = commodity_demand - commodity_in + nominal_charge_profile = np.where(nominal_set_point < 0, nominal_set_point, 0) + indx_charge = np.argwhere(nominal_charge_profile < 0).flatten() + excess_commodity_avail = np.abs( + np.abs(nominal_charge_profile)[indx_charge] - commodity_in[indx_charge] + ) + more_than_avail_charge_cmd = nominal_charge_profile[indx_charge] - excess_commodity_avail * 2 + # nominal_charge_profile[indx_charge] = more_than_avail_charge_cmd + nominal_set_point[indx_charge] = more_than_avail_charge_cmd + + prob.model.add_subsystem( + name="IVC1", + subsys=om.IndepVarComp(name="hydrogen_in", val=commodity_in, units="kg/h"), + promotes=["*"], + ) + + prob.model.add_subsystem( + name="IVC2", + subsys=om.IndepVarComp(name="hydrogen_demand", val=commodity_demand, units="kg/h"), + promotes=["*"], + ) + + prob.model.add_subsystem( + name="IVC3", + subsys=om.IndepVarComp(name="hydrogen_set_point", val=nominal_set_point, units="kg/h"), + promotes=["*"], + ) + + prob.model.add_subsystem( + "storage", + StoragePerformanceModel( + plant_config=plant_config, + tech_config={"model_inputs": model_inputs}, + ), + promotes=["*"], + ) + + prob.setup() + + prob.run_model() + + performance_model_config = model_inputs["performance_parameters"] + + charge_rate = prob.get_val("storage.max_charge_rate", units="kg/h")[0] + discharge_rate = prob.get_val("storage.max_charge_rate", units="kg/h")[0] + prob.get_val("storage.storage_capacity", units="kg")[0] + + # Test that discharge is always positive + with subtests.test("Discharge is always positive"): + assert np.all(prob.get_val("storage.storage_hydrogen_discharge", units="kg/h") >= 0) + + with subtests.test("Charge is always negative"): + assert np.all(prob.get_val("storage.storage_hydrogen_charge", units="kg/h") <= 0) + + with subtests.test("Charge + Discharge == storage_hydrogen_out"): + charge_plus_discharge = prob.get_val( + "storage.storage_hydrogen_charge", units="kg/h" + ) + prob.get_val("storage.storage_hydrogen_discharge", units="kg/h") + np.testing.assert_allclose( + charge_plus_discharge, prob.get_val("storage_hydrogen_out", units="kg/h"), rtol=1e-6 + ) + with subtests.test("Initial SOC is correct"): + assert ( + pytest.approx(prob.model.get_val("storage.SOC", units="unitless")[0], rel=1e-6) + == performance_model_config["init_soc_fraction"] + ) + + with subtests.test("Charge never exceeds charge rate"): + assert ( + prob.get_val("storage.storage_hydrogen_charge", units="kg/h").min() >= -1 * charge_rate + ) + + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + + with subtests.test("Discharge never exceeds discharge rate"): + assert ( + prob.get_val("storage.storage_hydrogen_discharge", units="kg/h").max() <= discharge_rate + ) + + with subtests.test("Discharge never exceeds demand"): + assert np.all( + prob.get_val("storage.storage_hydrogen_discharge", units="kg/h").max() + <= commodity_demand + ) + + with subtests.test("Expected discharge"): + expected_discharge = np.concat([np.zeros(18), np.ones(6)]) + np.testing.assert_allclose( + prob.get_val("storage.storage_hydrogen_discharge", units="kg/h"), + expected_discharge, + rtol=1e-6, + ) + + with subtests.test("Expected charge"): + expected_charge = np.concat([np.zeros(8), np.arange(-1, -9, -1), np.zeros(8)]) + np.testing.assert_allclose( + prob.get_val("storage.storage_hydrogen_charge", units="kg/h"), + expected_charge, + rtol=1e-6, + ) From f65d00f4a90c3bb49ae689652d60f5fdb5305cc1 Mon Sep 17 00:00:00 2001 From: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:33:19 -0600 Subject: [PATCH 2/4] fixed bug of charging with unavailable commodity --- h2integrate/storage/battery/pysam_battery.py | 6 +++++- h2integrate/storage/storage_baseclass.py | 14 +++++++++++++- .../storage/test/test_storage_performance_model.py | 4 +++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/h2integrate/storage/battery/pysam_battery.py b/h2integrate/storage/battery/pysam_battery.py index c20bc7b32..7848a1e54 100644 --- a/h2integrate/storage/battery/pysam_battery.py +++ b/h2integrate/storage/battery/pysam_battery.py @@ -180,6 +180,7 @@ def simulate( charge_rate: float, discharge_rate: float, storage_capacity: float, + commodity_available=list | np.ndarray, sim_start_index: int = 0, ): """Run the PySAM BatteryStateful model over a control window. @@ -236,13 +237,16 @@ def simulate( # expressed as a rate (commodity_rate_units). headroom = (soc_max - soc) * storage_capacity / self.dt_hr + # charge available based on the available input commodity + charge_available = commodity_available[sim_start_index + t] + # Calculate the max charge according to the charge rate and the simulation max_charge_input = min([charge_rate, -self.system_model.value("P_chargeable")]) # Clip to the most restrictive limit, # max(0, ...) guards against negative headroom when SOC # slightly exceeds soc_max. - actual_charge = max(0.0, min(headroom, max_charge_input, -cmd)) + actual_charge = max(0.0, min(headroom, max_charge_input, -cmd, charge_available)) # Update the charge command for the PySAM batttery cmd = -actual_charge diff --git a/h2integrate/storage/storage_baseclass.py b/h2integrate/storage/storage_baseclass.py index 65fa00f3e..7299b7bc4 100644 --- a/h2integrate/storage/storage_baseclass.py +++ b/h2integrate/storage/storage_baseclass.py @@ -269,6 +269,7 @@ def run_storage( "charge_rate": charge_rate, "discharge_rate": discharge_rate, "storage_capacity": storage_capacity, + "commodity_available": inputs[f"{self.commodity}_in"], } storage_commodity_out, soc = dispatch(self.simulate, kwargs, inputs) @@ -278,6 +279,7 @@ def run_storage( charge_rate=charge_rate, discharge_rate=discharge_rate, storage_capacity=storage_capacity, + commodity_available=inputs[f"{self.commodity}_in"], ) # determine storage charge and discharge @@ -342,6 +344,7 @@ def simulate( charge_rate: float, discharge_rate: float, storage_capacity: float, + commodity_available: list | np.ndarray, sim_start_index: int = 0, ): """Run the storage model over a control window of ``n_control_window`` timesteps. @@ -380,6 +383,8 @@ def simulate( ``commodity_rate_units`` (before discharge efficiency is applied). storage_capacity (float): Rated storage capacity in ``commodity_amount_units``. + commodity_available (list | np.ndarray): the input commodity available + to charge storage. sim_start_index (int, optional): Starting index for writing into persistent output arrays. Defaults to 0. @@ -422,11 +427,18 @@ def simulate( # expressed as a rate (commodity_rate_units). headroom = (soc_max - soc) * storage_capacity / self.dt_hr + # charge available based on the available input commodity + charge_available = commodity_available[sim_start_index + t] + # Clip to the most restrictive limit, then apply efficiency. # max(0, ...) guards against negative headroom when SOC # slightly exceeds soc_max. # correct headroom to not include charge_eff. - actual_charge = max(0.0, min(headroom / charge_eff, charge_rate, -cmd)) * charge_eff + + actual_charge = ( + max(0.0, min(headroom / charge_eff, charge_rate, -cmd, charge_available)) + * charge_eff + ) # Update SOC (actual_charge is in post-efficiency units) soc += actual_charge / storage_capacity diff --git a/h2integrate/storage/test/test_storage_performance_model.py b/h2integrate/storage/test/test_storage_performance_model.py index 6edcbd235..386e1d515 100644 --- a/h2integrate/storage/test/test_storage_performance_model.py +++ b/h2integrate/storage/test/test_storage_performance_model.py @@ -1084,7 +1084,9 @@ def test_generic_storage_charge_more_than_available(plant_config, subtests): ) with subtests.test("Expected charge"): - expected_charge = np.concat([np.zeros(8), np.arange(-1, -9, -1), np.zeros(8)]) + expected_charge = np.concat( + [np.zeros(8), np.arange(-6, -10, -1), np.array([-6]), np.zeros(11)] + ) np.testing.assert_allclose( prob.get_val("storage.storage_hydrogen_charge", units="kg/h"), expected_charge, From 255b7c319ba97276bb41b23c72d35accc6672b70 Mon Sep 17 00:00:00 2001 From: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:43:52 -0600 Subject: [PATCH 3/4] added subtests for charging less than available --- .../control/test/test_optimal_controllers.py | 20 +++++++++++++++ .../battery/test/test_pysam_battery.py | 14 +++++++++++ .../storage/test/test_storage_auto_sizing.py | 17 +++++++++++++ .../test/test_storage_performance_model.py | 25 +++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/h2integrate/control/test/test_optimal_controllers.py b/h2integrate/control/test/test_optimal_controllers.py index f1f1d5496..84528b11a 100644 --- a/h2integrate/control/test/test_optimal_controllers.py +++ b/h2integrate/control/test/test_optimal_controllers.py @@ -328,6 +328,11 @@ def test_min_operating_cost_load_following_battery_dispatch( rtol=1e-2, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("battery.storage_electricity_charge", units="kW") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= electricity_in[indx_charging]) + @pytest.mark.regression def test_optimal_control_with_generic_storage( @@ -477,6 +482,11 @@ def test_optimal_control_with_generic_storage( rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("h2_storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression def test_optimal_dispatch_with_autosizing_storage_demand_less_than_avg_in( @@ -547,6 +557,11 @@ def test_optimal_dispatch_with_autosizing_storage_demand_less_than_avg_in( rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("h2_storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression def test_optimal_dispatch_with_autosizing_storage_demand_is_avg_in( @@ -624,3 +639,8 @@ def test_optimal_dispatch_with_autosizing_storage_demand_is_avg_in( expected_charge, rtol=1e-6, ) + + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("h2_storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) diff --git a/h2integrate/storage/battery/test/test_pysam_battery.py b/h2integrate/storage/battery/test/test_pysam_battery.py index 1f47e22c5..9089e7c9b 100644 --- a/h2integrate/storage/battery/test/test_pysam_battery.py +++ b/h2integrate/storage/battery/test/test_pysam_battery.py @@ -190,6 +190,10 @@ def test_pysam_battery_performance_model_without_controller(plant_config, subtes expected_unused_electricity, rtol=1e-2, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage_electricity_charge", units="kW") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= electricity_in[indx_charging]) @pytest.mark.regression @@ -382,6 +386,11 @@ def test_pysam_battery_no_controller_change_capacity(plant_config, subtests): == init_charge_rate ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob_init.get_val("pysam_battery.storage_electricity_charge", units="kW") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= electricity_in[indx_charging]) + # Re-run and set the charge rate as half of what it was before prob = om.Problem() prob.model.add_subsystem( @@ -458,3 +467,8 @@ def test_pysam_battery_no_controller_change_capacity(plant_config, subtests): ) == 2.5 ) + + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("pysam_battery.storage_electricity_charge", units="kW") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= electricity_in[indx_charging]) diff --git a/h2integrate/storage/test/test_storage_auto_sizing.py b/h2integrate/storage/test/test_storage_auto_sizing.py index e7918ff5f..3aa247a78 100644 --- a/h2integrate/storage/test/test_storage_auto_sizing.py +++ b/h2integrate/storage/test/test_storage_auto_sizing.py @@ -188,6 +188,10 @@ def test_storage_autosizing_basic_performance_no_losses(plant_config, subtests): assert ( pytest.approx(prob.get_val("unused_hydrogen_out", units="kg/h").sum(), rel=1e-6) == 5.0 ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) @pytest.mark.regression @@ -285,6 +289,10 @@ def test_storage_autosizing_soc_bounds(plant_config, subtests): np.testing.assert_allclose( prob.get_val("hydrogen_out", units="kg/h"), commodity_demand, rtol=1e-6, atol=1e-10 ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) @pytest.mark.regression @@ -416,6 +424,11 @@ def test_storage_autosizing_losses(plant_config, subtests): atol=1e-10, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) @@ -507,3 +520,7 @@ def test_storage_autosizing_with_passthrough_controller(plant_config, subtests): rtol=1e-6, atol=1e-10, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) diff --git a/h2integrate/storage/test/test_storage_performance_model.py b/h2integrate/storage/test/test_storage_performance_model.py index 386e1d515..f07c40e08 100644 --- a/h2integrate/storage/test/test_storage_performance_model.py +++ b/h2integrate/storage/test/test_storage_performance_model.py @@ -184,6 +184,11 @@ def test_generic_storage_with_simple_control_dmd_lessthan_charge_rate(plant_conf rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) @@ -376,6 +381,11 @@ def test_generic_storage_with_simple_control_charge_rate_lessthan_demand(plant_c rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) @@ -537,6 +547,11 @@ def test_generic_storage_with_simple_control_zero_size(plant_config, subtests): == performance_model_config["init_soc_fraction"] ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) @@ -764,6 +779,11 @@ def test_generic_storage_with_simple_control_with_losses(plant_config, subtests) rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) @@ -958,6 +978,11 @@ def test_generic_storage_with_simple_control_with_losses_round_trip(plant_config rtol=1e-6, ) + with subtests.test("Charge never exceeds available commodity"): + charge_profile = prob.get_val("storage.storage_hydrogen_charge", units="kg/h") + indx_charging = np.argwhere(charge_profile).flatten() + assert np.all(np.abs(charge_profile)[indx_charging] <= commodity_in[indx_charging]) + @pytest.mark.regression @pytest.mark.parametrize("n_timesteps", [24]) From ade5a20ebf2a99c248c2d40b2ae46533c16600d1 Mon Sep 17 00:00:00 2001 From: elenya-grant <116225007+elenya-grant@users.noreply.github.com> Date: Thu, 9 Apr 2026 13:56:49 -0600 Subject: [PATCH 4/4] added test for technology naming and updated logic for using_feedback_control in storage baseclass setup() --- ...est_multistorage_pyomo_openloop_control.py | 98 +++++++++++++++++++ h2integrate/storage/storage_baseclass.py | 2 +- 2 files changed, 99 insertions(+), 1 deletion(-) diff --git a/h2integrate/control/test/test_multistorage_pyomo_openloop_control.py b/h2integrate/control/test/test_multistorage_pyomo_openloop_control.py index dc41da0fe..33841e0ae 100644 --- a/h2integrate/control/test/test_multistorage_pyomo_openloop_control.py +++ b/h2integrate/control/test/test_multistorage_pyomo_openloop_control.py @@ -788,3 +788,101 @@ def test_battery_pyomo_h2s_openloop(subtests, plant_config): h2s_expected_discharge, rtol=1e-6, ) + + +@pytest.mark.regression +@pytest.mark.parametrize("pyo_controllers", ["bat"]) +def test_battery_pyomo_battery_openloop(subtests, plant_config): + bat2_expected_discharge = np.concat([np.zeros(18), np.ones(6)]) + bat2_expected_charge = np.concat([np.zeros(8), np.arange(-1, -9, -1), np.zeros(8)]) + bat_expected_charge = np.concat( + [ + np.zeros(12), + np.array( + [ + -3988.62235554, + -3989.2357847, + -3989.76832626, + -3990.26170521, + -3990.71676106, + -3991.13573086, + -3991.52143699, + -3991.87684905, + -3992.20485715, + -3992.50815603, + -3992.78920148, + -3993.05020268, + ] + ), + ] + ) + bat_expected_discharge = np.concat( + [ + np.array( + [ + 5999.99995059, + 5990.56676743, + 5990.138959, + 5989.64831176, + 5989.08548217, + 5988.44193888, + 5987.70577962, + 5986.86071125, + 5985.88493352, + 5984.7496388, + 5983.41717191, + 5981.839478, + ] + ), + np.zeros(12), + ] + ) + + prob = om.Problem() + + # make h2 storage group + h2s_group = prob.model.add_subsystem("battery_2", om.Group()) + h2s_ivc_comp, h2s_perf_comp, h2s_control_comp = make_h2_storage_openloop_group(plant_config) + h2s_group.add_subsystem("IVC1", h2s_ivc_comp, promotes=["*"]) + h2s_group.add_subsystem("control", h2s_control_comp, promotes=["*"]) + h2s_group.add_subsystem("perf", h2s_perf_comp, promotes=["*"]) + + # make battery group + bat_rule_comp, bat_perf_comp, bat_control_comp, electricity_in = make_battery_pyo_group( + plant_config + ) + bat_group = prob.model.add_subsystem("battery", om.Group()) + bat_group.add_subsystem("IVC2", electricity_in, promotes=["*"]) + bat_group.add_subsystem("rule", bat_rule_comp, promotes=["*"]) + bat_group.add_subsystem("control", bat_control_comp, promotes=["*"]) + bat_group.add_subsystem("perf", bat_perf_comp, promotes=["*"]) + + prob.setup() + prob.run_model() + + with subtests.test("Battery #1: Expected charge"): + np.testing.assert_allclose( + prob.get_val("battery.storage_electricity_charge", units="kW")[:24], + bat_expected_charge, + rtol=1e-6, + ) + with subtests.test("Battery #1: Expected discharge"): + np.testing.assert_allclose( + prob.get_val("battery.storage_electricity_discharge", units="kW")[:24], + bat_expected_discharge, + rtol=1e-6, + ) + + # battery_2 is a "hydrogen battery" + with subtests.test("Battery #2: Expected charge"): + np.testing.assert_allclose( + prob.get_val("battery_2.storage_hydrogen_charge", units="kg/h")[:24], + bat2_expected_charge, + rtol=1e-6, + ) + with subtests.test("Battery #2: Expected discharge"): + np.testing.assert_allclose( + prob.get_val("battery_2.storage_hydrogen_discharge", units="kg/h")[:24], + bat2_expected_discharge, + rtol=1e-6, + ) diff --git a/h2integrate/storage/storage_baseclass.py b/h2integrate/storage/storage_baseclass.py index 7299b7bc4..28d96f822 100644 --- a/h2integrate/storage/storage_baseclass.py +++ b/h2integrate/storage/storage_baseclass.py @@ -181,7 +181,7 @@ def setup(self): for _source_tech, intended_dispatch_tech in self.options["plant_config"][ "tech_to_dispatch_connections" ]: - if any(intended_dispatch_tech in name for name in self.tech_group_name): + if any(intended_dispatch_tech == name for name in self.tech_group_name): self.add_discrete_input("pyomo_dispatch_solver", val=lambda: None) # set the using feedback control variable to True using_feedback_control = True