Skip to content
Draft
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
4 changes: 2 additions & 2 deletions examples/19_simple_dispatch/run_wind_battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@
)
ax[1].plot(
range(start_hour, end_hour),
model.prob.get_val("battery.electricity_unused_commodity", units="MW")[start_hour:end_hour],
model.prob.get_val("battery.unused_electricity_out", units="MW")[start_hour:end_hour],
linestyle=":",
label="Unused Electricity commodity (MW)",
linewidth=2,
)
ax[1].plot(
range(start_hour, end_hour),
model.prob.get_val("battery.electricity_unmet_demand", units="MW")[start_hour:end_hour],
model.prob.get_val("battery.unmet_electricity_demand_out", units="MW")[start_hour:end_hour],
linestyle=":",
label="Electricity Unmet Demand (MW)",
linewidth=2,
Expand Down
2 changes: 1 addition & 1 deletion examples/23_solar_wind_ng_demand/plant_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ technology_interconnections:
# connect NG feedstock to NG plant
- [combiner, electrical_load_demand, [electricity_out, electricity_in]]
# subtract wind and solar from demand
- [electrical_load_demand, natural_gas_plant, [electricity_unmet_demand, electricity_demand]]
- [electrical_load_demand, natural_gas_plant, [unmet_electricity_demand_out, electricity_demand]]
# give remaining load demand to natural gas plant
- [combiner, fin_combiner, electricity, cable]
- [natural_gas_plant, fin_combiner, electricity, cable]
Expand Down
12 changes: 6 additions & 6 deletions examples/24_solar_battery_grid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ The grid performance model handles:
- `electricity_in`: Power flowing INTO the grid (selling to grid) - limited by interconnection size
- `electricity_out`: Power flowing OUT OF the grid (buying from grid) - limited by interconnection size
- `electricity_sold`: Actual electricity sold (up to interconnection limit)
- `electricity_unmet_demand`: Demand that couldn't be met due to interconnection limit
- `electricity_excess`: Electricity that couldn't be sold due to interconnection limit
- `unmet_electricity_demand_out`: Demand that couldn't be met due to interconnection limit
- `unused_electricity_out`: Electricity that couldn't be sold due to interconnection limit

**Cost Model:**
- CapEx: Based on interconnection size ($/kW) plus fixed costs
Expand All @@ -72,16 +72,16 @@ Solar → Battery → [Grid Buy (purchases) | Grid Sell (sales)]

- Solar generates electricity
- Battery stores excess and follows 100 MW demand profile
- Grid Buy purchases electricity when battery cannot meet demand (via `electricity_unmet_demand` → `electricity_demand` connection)
- Grid Sell accepts excess electricity when battery has surplus (via `electricity_unused_commodity` → `electricity_in` connection)
- Grid Buy purchases electricity when battery cannot meet demand (via `unmet_electricity_demand_out` → `electricity_demand` connection)
- Grid Sell accepts excess electricity when battery has surplus (via `unused_electricity_out` → `electricity_in` connection)

### Technology Interconnections

```yaml
technology_interconnections: [
["solar", "battery", "electricity", "cable"],
["battery", "grid_buy", ["electricity_unmet_demand", "electricity_demand"]],
["battery", "grid_sell", ["electricity_unused_commodity", "electricity_in"]]
["battery", "grid_buy", ["unmet_electricity_demand_out", "electricity_demand"]],
["battery", "grid_sell", ["unused_electricity_out", "electricity_in"]]
]
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ def compute(self, inputs, outputs):
outputs (dict-like): Mapping of output variable names where results
will be written, including:

* ``{commodity}_unmet_demand``: Unmet demand.
* ``{commodity}_unused_commodity``: Curtailed production.
* ``{commodity}_out``: Actual output delivered.
* ``unmet_{commodity}_demand_out``: Unmet demand.
* ``unused_{commodity}_out``: Curtailed production.
* ``{commodity}_set_point``: Actual output delivered.

Notes:
All variables operate on a per-timestep basis and typically have
Expand All @@ -66,12 +66,14 @@ def compute(self, inputs, outputs):
remaining_demand = inputs[f"{commodity}_demand"] - inputs[f"{commodity}_in"]

# Calculate missed load and curtailed production
outputs[f"{commodity}_unmet_demand"] = np.where(remaining_demand > 0, remaining_demand, 0)
outputs[f"{commodity}_unused_commodity"] = np.where(
outputs[f"unmet_{commodity}_demand_out"] = np.where(
remaining_demand > 0, remaining_demand, 0
)
outputs[f"unused_{commodity}_out"] = np.where(
remaining_demand < 0, -1 * remaining_demand, 0
)

# Calculate actual output based on demand met and curtailment
outputs[f"{commodity}_set_point"] = (
inputs[f"{commodity}_in"] - outputs[f"{commodity}_unused_commodity"]
inputs[f"{commodity}_in"] - outputs[f"unused_{commodity}_out"]
)
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ def compute(self, inputs, outputs):

if self.config.min_utilization == 1.0:
# Calculate missed load and curtailed production
outputs[f"{commodity}_unmet_demand"] = np.where(
outputs[f"unmet_{commodity}_demand_out"] = np.where(
remaining_demand > 0, remaining_demand, 0
)
outputs[f"{commodity}_unused_commodity"] = np.where(
outputs[f"unused_{commodity}_out"] = np.where(
remaining_demand < 0, -1 * remaining_demand, 0
)
else:
Expand All @@ -289,14 +289,14 @@ def compute(self, inputs, outputs):
outputs[f"{commodity}_flexible_demand_profile"] = flexible_demand_profile
flexible_remaining_demand = flexible_demand_profile - inputs[f"{commodity}_in"]

outputs[f"{commodity}_unmet_demand"] = np.where(
outputs[f"unmet_{commodity}_demand_out"] = np.where(
flexible_remaining_demand > 0, flexible_remaining_demand, 0
)
outputs[f"{commodity}_unused_commodity"] = np.where(
outputs[f"unused_{commodity}_out"] = np.where(
flexible_remaining_demand < 0, -1 * flexible_remaining_demand, 0
)

# Calculate actual output based on demand met and curtailment
outputs[f"{commodity}_set_point"] = (
inputs[f"{commodity}_in"] - outputs[f"{commodity}_unused_commodity"]
inputs[f"{commodity}_in"] - outputs[f"unused_{commodity}_out"]
)
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ def setup(self):
)

self.add_output(
f"{commodity}_unmet_demand",
f"unmet_{commodity}_demand_out",
val=self.config.demand_profile,
shape=(n_timesteps),
units=self.config.commodity_rate_units,
desc=f"Remaining demand profile of {commodity}",
)

self.add_output(
f"{commodity}_unused_commodity",
f"unused_{commodity}_out",
val=0.0,
shape=(n_timesteps),
units=self.config.commodity_rate_units,
Expand All @@ -105,11 +105,11 @@ def setup(self):
desc=f"Production profile of {commodity}",
)

self.add_output(
f"total_{commodity}_unmet_demand",
units=self.config.commodity_rate_units,
desc="Total unmet demand",
)
# self.add_output(
# f"total_{commodity}_unmet_demand",
# units=self.config.commodity_rate_units,
# desc="Total unmet demand",
# )

def compute():
"""This method must be implemented by subclasses to define the
Expand Down
10 changes: 5 additions & 5 deletions h2integrate/control/test/test_openloop_controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,12 +562,12 @@ def test_demand_converter_controller(subtests):
)

with subtests.test("Check curtailment"):
assert prob.get_val("hydrogen_unused_commodity") == pytest.approx(
assert prob.get_val("unused_hydrogen_out") == pytest.approx(
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0]
)

with subtests.test("Check missed load"):
assert prob.get_val("hydrogen_unmet_demand") == pytest.approx(
assert prob.get_val("unmet_hydrogen_demand_out") == pytest.approx(
[5.0, 4.0, 3.0, 2.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0]
)

Expand Down Expand Up @@ -644,7 +644,7 @@ def test_flexible_demand_converter_controller(subtests, variable_h2_production_p
assert np.all(flexible_total_demand <= end_use_rated_demand)

with subtests.test("Check curtailment"): # failed
assert np.sum(prob.get_val("hydrogen_unused_commodity", units="kg")) == pytest.approx(6.6)
assert np.sum(prob.get_val("unused_hydrogen_out", units="kg")) == pytest.approx(6.6)

# check ramping constraints and turndown constraints are met
with subtests.test("Check turndown ratio constraint"):
Expand Down Expand Up @@ -672,13 +672,13 @@ def test_flexible_demand_converter_controller(subtests, variable_h2_production_p
# any commodity in)
with subtests.test("Check that flexible demand is greater than hydrogen_in"):
hydrogen_available = variable_h2_production_profile - prob.get_val(
"hydrogen_unused_commodity", units="kg"
"unused_hydrogen_out", units="kg"
)
assert np.all(flexible_total_demand >= hydrogen_available)

with subtests.test("Check that remaining demand was calculated properly"):
unmet_demand = flexible_total_demand - hydrogen_available
assert np.all(unmet_demand == prob.get_val("hydrogen_unmet_demand", units="kg"))
assert np.all(unmet_demand == prob.get_val("unmet_hydrogen_demand_out", units="kg"))


@pytest.mark.regression
Expand Down
Loading