-
Notifications
You must be signed in to change notification settings - Fork 33
Peak load management heuristic control #641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 54 commits
933ae89
90b82d8
d338cce
e8a2dfb
7276db6
226f0a4
6fc22a7
ecc0abd
db0c72a
d5b4250
b7b2573
9b021ee
ad97f44
b4508be
4473244
4b6e25f
d7774d2
74fc2ed
b456d75
a624bd4
0aa1ee2
767eab2
cc03ac3
e3d824f
7b3d3da
5e6ef34
1a344e6
ca878ed
a0bb555
cef5b02
fe01f8f
5527570
52f5e45
af66754
797e1d6
830b6ee
dfe8380
9c0b212
7cbfe2f
725838b
55d6d7a
b5689a4
83c0e4f
6ebe8ea
b0f3036
f63fd63
8d3d82a
15d178a
983d770
b65478e
6cfc269
71d9737
840304d
2867695
5a81860
01d44c5
7c878cb
617f819
30484e3
a1bab83
9d7b7a3
c0a1561
515557d
2e2820a
e103abe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,10 @@ | |
| # Open-Loop Controllers | ||
|
|
||
| ## Open-Loop Storage Controllers | ||
| The open-loop storage controllers can be attached as the control strategy in the `tech_config` for various storage converters (e.g., battery or hydrogen storage). There are two controller types for storage: | ||
| 1. Pass-through Controller - passes the commodity flow to the output without any modification | ||
| 2. Demand Open-Loop Storage Controller - uses simple logic to attempt to meet demand using the storage technology. | ||
| The open-loop storage controllers can be attached as the control strategy in the `tech_config` for various storage converters (e.g., battery or hydrogen storage). There are three controller types for storage: | ||
| 1. [Simple Open-Loop Storage Controller](#pass-through-controller) — passes the commodity flow to the output with only minimal or no modifications. | ||
| 2. [Demand Open-Loop Storage Controller](#demand-open-loop-storage-controller) — uses simple logic to attempt to meet demand using the storage technology. | ||
| 3. [Peak Load Management Open-Loop Storage Controller](#peak-load-management-open-loop-storage-controller) — computes a peak-shaving dispatch schedule to reduce demand peaks, supporting one or two demand profiles with configurable event limits and time windows. | ||
|
|
||
| (pass-through-controller)= | ||
| ### Simple Open-Loop Storage Controller | ||
|
|
@@ -26,3 +27,98 @@ An example of an N2 diagram for a system using the open-loop control framework f | |
| For examples of how to use the `DemandOpenLoopStorageController` open-loop control framework, see the following: | ||
| - `examples/14_wind_hydrogen_dispatch/` | ||
| - `examples/19_simple_dispatch/` | ||
|
|
||
| (peak-load-management-open-loop-storage-controller)= | ||
| ### Peak Load Management Open-Loop Storage Controller | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is very detailed documentation! Since this section is so detailed - should this be moved to a separate file that's linked in this file? Non-blocking, just a thought!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is getting close, but not enough to warrant a separate file. I'm open for discussion, but am leaving as is unless I hear more desire for the additional file. |
||
| The `PeakLoadManagementOpenLoopStorageController` computes and executes a peak-shaving dispatch schedule assuming perfect forecasting. It is designed for reducing peak loads, not meeting a specific demand, using either one or two loads for determining peaks. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a note callout saying that this strategy operates on an assumed daily cycle? that would help make it more obvious to a user the limitations of the method. (at least that's my understanding after reading the method -- that could be wrong)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done
kbrunik marked this conversation as resolved.
|
||
|
|
||
| The controller supports two demand profiles: | ||
|
|
||
| - **`demand_profile`** — the local or sub-system demand. Peaks within a configurable daily time window (`peak_range`) are identified as candidate discharge targets. | ||
| - **`demand_profile_2`** — an optional upstream or supervisory demand. When provided, an operator can override the local peak schedule up to a configurable number of events per period (e.g., three times per week). Peaks are determined as the highest n peaks in each period. | ||
|
kbrunik marked this conversation as resolved.
|
||
|
|
||
| The `dispatch_priority_demand_profile` parameter selects which profile acts as the override schedule. On days where the priority profile flags a peak, the controller follows that schedule; on all other days it falls back to the other profile. | ||
|
|
||
| **Dispatch logic (state machine)** | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After reading all of the docstrings, I think it could be helpful to expand this a bit more based on all of the methods getting employed to calculate this. I appreciate the simplicity of Discharge, Charge and Idle but maybe after this logic you could include a bit more?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm happy to add more, but after reviewing it I'm not sure what else would be helpful at this level. Can you be more specific about what details you would like to see at the high-level docs rather than left in the doc strings? |
||
|
|
||
| 1. **Discharge** — begins `advance_discharge_period` before the next scheduled peak and runs until `min_soc_fraction` is reached. | ||
| 2. **Charge** — resumes after `delay_charge_period` has elapsed since the end of discharge, subject to the `allow_charge_in_peak_range` flag which can block recharging during the peak windows. | ||
| 3. **Idle** — all other timesteps; set-point is zero. | ||
|
|
||
| An example output for the first week of a one-year simulation is shown below. Orange shading marks the 12:00–19:00 daily peak window. The top panel shows both demand profiles; the second panel shows battery state of charge; the third shows battery charge/discharge power; the fourth shows the resulting net demand. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you be able to expand this description to highlight how the different demands are impacting the dispatch as seen in the figure? Also if there are other interesting pieces of the dispatch in this particular example that exemplify the dispatch strategy it would be really awesome if you could add more description here.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
|
||
|  | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't rendering in the docs.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked in the CI tests and I see the figure render just fine. Let me know if you still can't see it. |
||
|
|
||
| For an example of how to use the `PeakLoadManagementOpenLoopStorageController`, see: | ||
| - `examples/33_peak_load_management/` | ||
|
|
||
| #### Configuration | ||
| The controller is defined within the `tech_config` and requires the shared storage parameters plus a `control_parameters` block: | ||
|
kbrunik marked this conversation as resolved.
Outdated
|
||
|
|
||
| **Storage system parameters used by the controller** | ||
|
|
||
| | Field | Type | Description | | ||
| | --- | --- | --- | | ||
| | `commodity` | `str` | Commodity name (e.g., `electricity`). | | ||
| | `commodity_rate_units` | `str` | Rate units (e.g., `kW`). | | ||
| | `demand_profile` | scalar or list | Local demand timeseries. | | ||
| | `max_capacity` | `float` | Storage capacity in commodity amount units. | | ||
| | `max_charge_rate` | `float` | Maximum charge rate. | | ||
| | `max_discharge_rate` | `float` | Maximum discharge rate (required if `charge_equals_discharge: false`). | | ||
| | `charge_equals_discharge` | `bool` | If `true`, discharge rate equals `max_charge_rate`. | | ||
| | `max_soc_fraction` | `float` | Upper SOC limit as a fraction (0–1). | | ||
| | `min_soc_fraction` | `float` | Lower SOC limit as a fraction (0–1). | | ||
| | `init_soc_fraction` | `float` | Initial SOC as a fraction (0–1). | | ||
| | `charge_efficiency` | `float` | Charging efficiency (0–1). | | ||
| | `discharge_efficiency` | `float` | Discharging efficiency (0–1). | | ||
|
|
||
| **Control-specific parameters** | ||
|
|
||
| | Field | Type | Description | | ||
| | --- | --- | --- | | ||
| | `demand_profile_2` | scalar, list, or `null` | Optional supervisory/upstream demand timeseries. | | ||
| | `dispatch_priority_demand_profile` | `str` | Which profile controls scheduling: `demand_profile` or `demand_profile_2`. | | ||
| | `n_override_events` | `int \| null` | Maximum supervisory dispatch events allowed per `override_events_period`. | | ||
| | `override_events_period` | `str \| null` | Pandas period alias for resetting the event counter (e.g., `W` for weekly, `M` for monthly). | | ||
| | `peak_range` | `dict` | Daily window for local peak detection. Keys `start` and `end` as `HH:MM:SS` strings. | | ||
| | `advance_discharge_period` | `dict` | Lead time before a peak to start discharging. Keys `units` (e.g., `h`) and `val`. | | ||
| | `delay_charge_period` | `dict` | Wait after discharge before recharging. Keys `units` and `val`. | | ||
| | `allow_charge_in_peak_range` | `bool` | If `false`, charging is blocked during `peak_range`. | | ||
| | `min_peak_proximity` | `dict` | Minimum separation between retained peak events. Keys `units` and `val`. | | ||
|
|
||
| ```yaml | ||
| control_strategy: | ||
| model: PeakLoadManagementOpenLoopStorageController | ||
| model_inputs: | ||
| shared_parameters: | ||
| commodity: electricity | ||
| commodity_rate_units: kW | ||
| max_charge_rate: 300.0 | ||
| max_capacity: 1200.0 | ||
| max_soc_fraction: 0.9 | ||
| min_soc_fraction: 0.1 | ||
| init_soc_fraction: 0.9 | ||
| demand_profile: !include demand_profile.yaml | ||
| charge_efficiency: 1.0 | ||
| discharge_efficiency: 1.0 | ||
| control_parameters: | ||
| max_discharge_rate: 300.0 | ||
| charge_equals_discharge: true | ||
|
elenya-grant marked this conversation as resolved.
Outdated
|
||
| demand_profile_2: !include demand_profile_2.yaml | ||
| dispatch_priority_demand_profile: demand_profile_2 | ||
| n_override_events: 3 | ||
| override_events_period: W | ||
| peak_range: | ||
| start: "12:00:00" | ||
| end: "19:00:00" | ||
| advance_discharge_period: | ||
| units: h | ||
| val: 1 | ||
| delay_charge_period: | ||
| units: h | ||
| val: 4 | ||
| allow_charge_in_peak_range: false | ||
| min_peak_proximity: | ||
| units: h | ||
| val: 4 | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| name: H2Integrate_config | ||
| system_summary: Peak load management dispatch | ||
| driver_config: driver_config.yaml | ||
| technology_config: tech_config.yaml | ||
| plant_config: plant_config.yaml |
Uh oh!
There was an error while loading. Please reload this page.