diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc025463..a374693d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - Updated option to pass variables in technology interconnections to allow for different variable names from source to destination in the format `[source_tech, dest_tech, (source_tech_variable, dest_tech_variable)]` - Added `simulation` section under `plant_config['plant']` that has information such as number of timesteps in the simulation, time step interval in seconds, simulation start time, and time zone. - Added `"custom_electrolyzer_cost"` model, an electrolyzer cost model that allows for user-defined capex and opex values +- Made `pipe` and `cable` substance-agnostic rather than hard-coded for `hydrogen` and `electricity` ## 0.3.0 [May 2 2025] diff --git a/examples/05_wind_h2_opt/driver_config.yaml b/examples/05_wind_h2_opt/driver_config.yaml index 086eb1077..f2ae451a4 100644 --- a/examples/05_wind_h2_opt/driver_config.yaml +++ b/examples/05_wind_h2_opt/driver_config.yaml @@ -7,11 +7,11 @@ general: driver: optimization: flag: True + solver: COBYLA tol: 0.1 catol: 10000 max_iter: 100 - solver: COBYLA - rhobeg: 30 + rhobeg: 10 debug_print: True design_variables: @@ -35,4 +35,4 @@ objective: recorder: flag: True file: "wind_h2_opt.sql" - includes: ["LCOH"] + includes: ["*"] diff --git a/h2integrate/core/h2integrate_model.py b/h2integrate/core/h2integrate_model.py index 12607ed8e..85730d076 100644 --- a/h2integrate/core/h2integrate_model.py +++ b/h2integrate/core/h2integrate_model.py @@ -463,7 +463,9 @@ def connect_technologies(self): connection_name = f"{source_tech}_to_{dest_tech}_{transport_type}" # Create the transport object - connection_component = self.supported_models[transport_type]() + connection_component = self.supported_models[transport_type]( + transport_item=transport_item + ) # Add the connection component to the model self.plant.add_subsystem(connection_name, connection_component) diff --git a/h2integrate/transporters/cable.py b/h2integrate/transporters/cable.py index 1261b70b4..cd25dcfe6 100644 --- a/h2integrate/transporters/cable.py +++ b/h2integrate/transporters/cable.py @@ -6,21 +6,26 @@ class CablePerformanceModel(om.ExplicitComponent): Pass-through cable with no losses. """ + def initialize(self): + self.options.declare("transport_item", values=["electricity"]) + def setup(self): + self.input_name = self.options["transport_item"] + "_in" + self.output_name = self.options["transport_item"] + "_out" self.add_input( - "electricity_in", + self.input_name, val=0.0, shape_by_conn=True, - copy_shape="electricity_out", + copy_shape=self.output_name, units="kW", ) self.add_output( - "electricity_out", + self.output_name, val=0.0, shape_by_conn=True, - copy_shape="electricity_in", + copy_shape=self.input_name, units="kW", ) def compute(self, inputs, outputs): - outputs["electricity_out"] = inputs["electricity_in"] + outputs[self.output_name] = inputs[self.input_name] diff --git a/h2integrate/transporters/pipe.py b/h2integrate/transporters/pipe.py index 077e080db..f1ef7300d 100644 --- a/h2integrate/transporters/pipe.py +++ b/h2integrate/transporters/pipe.py @@ -6,21 +6,28 @@ class PipePerformanceModel(om.ExplicitComponent): Pass-through pipe with no losses. """ + def initialize(self): + self.options.declare( + "transport_item", values=["hydrogen", "co2", "methanol", "ammonia", "nitrogen"] + ) + def setup(self): + self.input_name = self.options["transport_item"] + "_in" + self.output_name = self.options["transport_item"] + "_out" self.add_input( - "hydrogen_in", + self.input_name, val=0.0, shape_by_conn=True, - copy_shape="hydrogen_out", + copy_shape=self.output_name, units="kg/s", ) self.add_output( - "hydrogen_out", + self.output_name, val=0.0, shape_by_conn=True, - copy_shape="hydrogen_in", + copy_shape=self.input_name, units="kg/s", ) def compute(self, inputs, outputs): - outputs["hydrogen_out"] = inputs["hydrogen_in"] + outputs[self.output_name] = inputs[self.input_name] diff --git a/h2integrate/transporters/test/test_pipe.py b/h2integrate/transporters/test/test_pipe.py new file mode 100644 index 000000000..32718fb12 --- /dev/null +++ b/h2integrate/transporters/test/test_pipe.py @@ -0,0 +1,40 @@ +import pytest +import openmdao.api as om +from pytest import approx + +from h2integrate.transporters.pipe import PipePerformanceModel + + +def test_pipe_with_hydrogen(): + """Test the pipe transport with hydrogen as transport_item.""" + + # Create the pipe component with hydrogen as transport item + pipe = PipePerformanceModel(transport_item="hydrogen") + + # Create OpenMDAO problem and add the component + prob = om.Problem() + prob.model.add_subsystem("pipe", pipe, promotes=["*"]) + + # Add independent variable component for input + ivc = om.IndepVarComp() + ivc.add_output("hydrogen_in", val=10.0, units="kg/s") + prob.model.add_subsystem("ivc", ivc, promotes=["*"]) + + # Setup and run the model + prob.setup() + prob.set_val("hydrogen_in", 10.0, units="kg/s") + prob.run_model() + + # Check that output equals input (pass-through pipe with no losses) + hydrogen_in = prob.get_val("hydrogen_in", units="kg/s") + hydrogen_out = prob.get_val("hydrogen_out", units="kg/s") + + assert hydrogen_out == approx(hydrogen_in, rel=1e-10) + assert hydrogen_out == approx(10.0, rel=1e-10) + + +def test_pipe_with_invalid_transport_item(): + """Test that pipe raises an error with invalid transport_item.""" + with pytest.raises(ValueError) as excinfo: + PipePerformanceModel(transport_item="invalid_item") + assert "Value ('invalid_item')" in str(excinfo.value)