Skip to content

Commit 6d4caff

Browse files
elenya-grantkbrunikjohnjasa
authored
Remove system-level outputs from storage and replace with demand component (follow-on to 631) (#666)
* removed system level calcs from storage and updated most tests * updated examples with storage but dont use storage as a commodity_stream in finances * updated examples with storage defined as a commodity_stream for a finance subgroup * added time_step_bounds to demand components * added test for example 23 * added example for different demand between storage and demand component * added demo for the demand components using example 13 * made it so demand is only input to battery performance model if using feedback control * added standard_capacity_factor as output from storage * added doc page for storage performance models --------- Co-authored-by: kbrunik <102193481+kbrunik@users.noreply.github.com> Co-authored-by: John Jasa <johnjasa11@gmail.com> Co-authored-by: kbrunik <kbrunik@gmail.com>
1 parent 22931d7 commit 6d4caff

60 files changed

Lines changed: 10229 additions & 278 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
- The `DemandOpenLoopConverterController` has been renamed to `GenericDemandComponent`
5353
- Modified CI setup so Windows is temporarily disabled and also so unit, regression, and integration tests are run in separate jobs to speed up testing and provide more information on test failures. [PR 668](https://github.com/NatLabRockies/H2Integrate/pull/668)
5454
- Added infrastructure for running models with non-hourly time steps via a class attribute `_time_step_bounds` and sets new time step bounds of 5-minutes to 1-hour for the grid components. [PR 653](https://github.com/NatLabRockies/H2Integrate/pull/653) and [PR 671](https://github.com/NatLabRockies/H2Integrate/pull/671)
55+
- Remove demand-related outputs from storage performance models and replace usage with demand components [PR 666](https://github.com/NatLabRockies/H2Integrate/pull/666)
5556

5657
## 0.7.2 [April 9, 2026]
5758

docs/_toc.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,22 @@ parts:
3636
- file: technology_models/atb_costs_pv.md
3737
- file: technology_models/atb_costs_wind.md
3838
- file: technology_models/co2.md
39-
- file: technology_models/simple_generic_storage.md
4039
- file: technology_models/methanol.md
4140
- file: technology_models/ammonia.md
42-
- file: technology_models/pysam_battery.md
4341
- file: technology_models/wind_plant_ard.md
4442
- file: technology_models/geologic_hydrogen.md
4543
- file: technology_models/grid
46-
- file: technology_models/hydrogen_storage.md
4744
- file: technology_models/h2_fuel_cell.md
4845
- file: technology_models/h2_smr.md
4946
- file: technology_models/iron_ewin.md
5047
- file: technology_models/iron_mine.md
5148
- file: technology_models/iron_dri.md
5249
- file: technology_models/steel_eaf.md
50+
- file: technology_models/storage_models_index.md
51+
sections:
52+
- file: technology_models/simple_generic_storage.md
53+
- file: technology_models/pysam_battery.md
54+
- file: technology_models/hydrogen_storage.md
5355
- caption: Resource Models
5456
chapters:
5557
- file: resource/resource_index
@@ -72,6 +74,7 @@ parts:
7274
- caption: Demand
7375
chapters:
7476
- file: demand/demand_components
77+
- file: demand/demand_demo
7578
- caption: Finance Models
7679
chapters:
7780
- file: finance_models/financial_analyses

docs/api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@
1515
storage
1616
transporters
1717
tools
18+
demand
1819
```

docs/control/controller_demonstrations.md

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,51 @@ kernelspec:
1717
from pathlib import Path
1818
from matplotlib import pyplot as plt
1919
from h2integrate.core.h2integrate_model import H2IntegrateModel
20+
from h2integrate import EXAMPLE_DIR
21+
2022
```
2123

2224
## Hydrogen Dispatch
2325

2426
The following example is an expanded form of `examples/14_wind_hydrogen_dispatch`.
2527

2628
Here, we're highlighting the dispatch controller setup from
27-
`examples/14_wind_hydrogen_dispatch/inputs/tech_config.yaml`. Please note some sections are removed
28-
simply to highlight the controller sections
29+
`examples/14_wind_hydrogen_dispatch/inputs/tech_config.yaml`. Please note some sections are removed simply to highlight the controller sections
30+
31+
```{literalinclude} ../../examples/14_wind_hydrogen_dispatch/inputs/tech_config.yaml
32+
:language: yaml
33+
:lineno-start: 52
34+
:linenos: true
35+
:lines: 52,53-54,57-58,59-71
36+
```
37+
38+
We also include a demand technology to calculate how much demand is met, how much commodity is unused to meet the demand, and how much demand is remaining:
2939

3040
```{literalinclude} ../../examples/14_wind_hydrogen_dispatch/inputs/tech_config.yaml
3141
:language: yaml
32-
:lineno-start: 54
42+
:lineno-start: 79
3343
:linenos: true
34-
:lines: 54,59-61,67-74
44+
:lines: 79-86
3545
```
3646

47+
3748
Using the primary configuration, we can create, run, and postprocess an H2Integrate model.
3849

3950
```{code-cell} ipython3
4051
# Create an H2Integrate model
41-
model = H2IntegrateModel(Path("../../examples/14_wind_hydrogen_dispatch/inputs/h2i_wind_to_h2_storage.yaml"))
52+
model = H2IntegrateModel(EXAMPLE_DIR/"14_wind_hydrogen_dispatch"/"inputs"/"h2i_wind_to_h2_storage.yaml")
4253
4354
# Run the model
4455
model.run()
45-
model.post_process()
4656
```
4757

4858
Now, we can visualize the demand profiles over time.
4959

5060
```{code-cell} ipython3
5161
fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, figsize=(8, 6), layout="tight")
5262
53-
start_hour = 0
54-
end_hour = 200
55-
total_time_steps = model.prob.get_val("h2_storage.SOC").size
56-
demand_profile = [
57-
model.technology_config["technologies"]["h2_storage"]["model_inputs"]["shared_parameters"][
58-
"demand_profile"
59-
]
60-
* 1e-3
61-
] * total_time_steps
63+
start_hour = 800
64+
end_hour = 1000
6265
xvals = list(range(start_hour, end_hour))
6366
6467
ax1.plot(
@@ -74,41 +77,41 @@ ax2.plot(
7477
)
7578
ax2.plot(
7679
xvals,
77-
model.prob.get_val("h2_storage.unused_hydrogen_out", units="t/h")[start_hour:end_hour],
80+
model.prob.get_val("h2_load_demand.unused_hydrogen_out", units="t/h")[start_hour:end_hour],
7881
linestyle=":",
7982
label="H$_2$ Unused (kg)",
8083
)
8184
ax2.plot(
8285
xvals,
83-
model.prob.get_val("h2_storage.unmet_hydrogen_demand_out", units="t/h")[start_hour:end_hour],
86+
model.prob.get_val("h2_load_demand.unmet_hydrogen_demand_out", units="t/h")[start_hour:end_hour],
8487
linestyle=":",
8588
label="H$_2$ Unmet Demand (kg)",
8689
)
8790
ax2.plot(
8891
xvals,
89-
model.prob.get_val("h2_storage.hydrogen_out", units="t/h")[start_hour:end_hour],
92+
model.prob.get_val("h2_load_demand.hydrogen_out", units="t/h")[start_hour:end_hour],
9093
linestyle="-",
9194
label="H$_2$ Delivered (kg)",
9295
)
9396
ax2.plot(
9497
xvals,
95-
demand_profile[start_hour:end_hour],
98+
model.prob.get_val("h2_load_demand.hydrogen_demand", units="t/h")[start_hour:end_hour],
9699
linestyle="--",
97100
label="H$_2$ Demand (kg)",
98101
)
99102
100103
ax1.set_ylabel("SOC (%)")
101104
ax1.grid()
102105
ax1.set_axisbelow(True)
103-
ax1.set_xlim(0, 200)
104-
ax1.set_ylim(0, 50)
106+
ax1.set_xlim(start_hour, end_hour)
107+
ax1.set_ylim(60, 100)
105108
106109
ax2.set_ylabel("H$_2$ Hourly (t)")
107110
ax2.set_xlabel("Timestep (hr)")
108111
ax2.grid()
109112
ax2.set_axisbelow(True)
110-
ax2.set_ylim(0, 20)
111-
ax2.set_yticks(range(0, 21, 2))
113+
ax2.set_ylim(0, 18)
114+
ax2.set_yticks(range(0, 19, 2))
112115
113116
plt.legend(ncol=3)
114117
fig.show()

docs/demand/demand_components.md

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
1-
# Demand components
2-
3-
- [`GenericDemandComponent`](#generic-demand-component)
4-
- [`FlexibleDemandComponent`](#flexible-demand-component)
1+
# Demand Components
52

63
Demand components define rule-based logic for meeting commodity demand profiles without using dynamic system feedback. These components operate independently at each timestep.
74

85
This page documents two core demand types:
9-
1. Generic Demand Component — meets a fixed demand profile.
10-
2. Flexible Demand Component — adjusts demand up or down within flexible bounds.
6+
1. [`GenericDemandComponent`](#generic-demand-component) — meets a fixed demand profile.
7+
2. [`FlexibleDemandComponent`](#flexible-demand-component) — adjusts demand up or down within flexible bounds.
8+
9+
10+
(demand-component-inputs-and-outputs)=
11+
## Demand component inputs and outputs
12+
The inputs to the demand components are the `{commodity}_demand` profile and the `{commodity}_in` profile. The `{commodity}_in` profile is the initial commodity used to satisfy the demand. Suppose the `{commodity}_in` (pink) and `{commodity}_demand` (green) profiles look like whats shown below:
13+
14+
![](./figures/demand_inputs.png)
15+
16+
The demand components then compute the following output profiles:
17+
- `unmet_{commodity}_demand_out`: Unmet demand (non-zero when supply < demand, otherwise 0.)
18+
- `unused_{commodity}_out`: Unused commodity (non-zero when supply > demand, otherwise 0.)
19+
20+
![](./figures/demand_calcs.png)
21+
22+
- `commodity_out`: Delivered output (commodity supplied to demand sink)
23+
24+
![](./figures/demand_commodity_out.png)
25+
26+
The demand components also compute the following outputs:
27+
- `capacity_factor`: the ratio of the demand that's been met to the full demand
28+
- `rated_commodity_production`: the maximum value of the demand profile
29+
1130

1231
(generic-demand-component)=
1332
### Generic Demand Component

0 commit comments

Comments
 (0)