Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
141 commits
Select commit Hold shift + click to select a range
0abe06f
added test to highlight error
elenya-grant Apr 9, 2026
f65d00f
fixed bug of charging with unavailable commodity
elenya-grant Apr 9, 2026
255b7c3
added subtests for charging less than available
elenya-grant Apr 9, 2026
ade5a20
added test for technology naming and updated logic for using_feedback…
elenya-grant Apr 9, 2026
27ca0a9
Merge remote-tracking branch 'h2i_upstream/develop' into dispatch/sto…
elenya-grant Apr 9, 2026
85eda16
Merge remote-tracking branch 'h2i_upstream/develop' into dispatch/sto…
elenya-grant Apr 13, 2026
696ffe6
Merge branch 'develop' into dispatch/storage_fixes
johnjasa Apr 14, 2026
aacc334
merged in develop
elenya-grant Apr 28, 2026
a2fe782
other fixes from merge
elenya-grant Apr 28, 2026
3d0e272
Add system_level_control to the CI
johnjasa Apr 28, 2026
d13d25a
added control classifiers to key technology models
elenya-grant Apr 28, 2026
c51d33d
added curtailable component
elenya-grant Apr 28, 2026
0e9dd0b
added logic in h2imodel to add curtailment component to curtailment c…
elenya-grant Apr 28, 2026
0cedd82
Working through start of system level controller
johnjasa Apr 28, 2026
6a51fe1
Merge pull request #713 from elenya-grant/draft_control_setup
johnjasa Apr 29, 2026
0aff134
Added initial system level control example
johnjasa Apr 29, 2026
9ff6fae
Fixed SLC example
johnjasa Apr 29, 2026
08f8790
Reordering SLC settings
johnjasa Apr 29, 2026
d84566f
Merge branch 'develop' of https://github.com/NREL/H2Integrate into sy…
johnjasa Apr 29, 2026
733c636
Updating the SLC example
johnjasa Apr 29, 2026
d91e8ae
Added curtailment
johnjasa Apr 29, 2026
fc6bd5f
WIP: adding battery example for SLC
johnjasa Apr 29, 2026
efd3093
Improving plotting for battery SLC example
johnjasa Apr 29, 2026
59f9b16
Moved combiner and changed battery model
johnjasa Apr 29, 2026
0fdfde2
Changed example so wind power is sometimes curtailed after charging b…
johnjasa Apr 29, 2026
2e428b3
updated plotting script
johnjasa Apr 29, 2026
237df21
added marker to curtailment component test
elenya-grant Apr 29, 2026
cb9d053
added super basic SLC tests to make sure examples dont break
elenya-grant Apr 29, 2026
1ef9743
fixed example tests
elenya-grant Apr 29, 2026
748be32
Minor name clarifications within SLC
johnjasa Apr 29, 2026
f8294c6
Adding a notion of price-considering SLCs
johnjasa Apr 29, 2026
3bcbc2f
WIP: working on marginal costs for SLC
johnjasa Apr 29, 2026
6dff236
Updating SLC example to be simpler
johnjasa Apr 29, 2026
c2123f8
Removing prior SLC file
johnjasa Apr 30, 2026
9df4fd7
Consolidating methods for SLC
johnjasa Apr 30, 2026
9567318
Moving SLC strategy definitions
johnjasa Apr 30, 2026
8910d36
moved solver options to a config class
elenya-grant May 1, 2026
553ed20
minor fixes
elenya-grant May 1, 2026
5ca4d15
Merging
johnjasa May 4, 2026
2a741ba
Multi-commodity systems for SLC (#717)
elenya-grant May 4, 2026
8b6f2c1
added framework to interface with storage controllers and example
elenya-grant May 5, 2026
23a251a
fix so curtailment only applied if using SLC
elenya-grant May 5, 2026
b271026
made slc_config an input option
elenya-grant May 5, 2026
c4d95bb
actually make it so slc get option of slc conig and fixed bug in appl…
elenya-grant May 5, 2026
8de0ff1
added check for slc in apply_curtailment() method
elenya-grant May 5, 2026
7a4752a
updated so slc_config is an input option and added control config cla…
elenya-grant May 5, 2026
5881e07
Adding marginal_cost calcs
johnjasa May 5, 2026
3cf8cd5
Merging
johnjasa May 5, 2026
d084f69
replaced lists of tech control classifiers with the dictionary
elenya-grant May 5, 2026
6010b5c
merged in upstream
elenya-grant May 5, 2026
d520335
merging
johnjasa May 6, 2026
a11e37c
Directly connected demand profile
johnjasa May 6, 2026
db9c9c0
Shared commodity sell price as input from finance subgroups
johnjasa May 6, 2026
c101048
Merging
johnjasa May 6, 2026
887873f
Fixed bad set-point behavior
johnjasa May 6, 2026
93a69c0
Uploading complex profit maximization
johnjasa May 6, 2026
1085a68
Backmerging, all examples in folder 35 run
johnjasa May 6, 2026
e4a94bd
tried to add helper methods to slc baseclass
elenya-grant May 6, 2026
9a5cfdc
added marginal cost to cost models that dont inherit costmodelbaseconfig
elenya-grant May 6, 2026
afb0af3
updated cost model baseclass handling of marginal cost
elenya-grant May 6, 2026
a6a841d
updated so that demand is properly output from slc for storage contro…
elenya-grant May 6, 2026
f06736e
merged in upstream
elenya-grant May 6, 2026
9984c70
fixed example 33
elenya-grant May 6, 2026
18732aa
Merge branch 'system_level_control' into marginal_costs
kbrunik May 6, 2026
fb219d5
Minor typographical changes
johnjasa May 6, 2026
4ee228b
Merge branch 'system_level_control' into slc/storge_control_interfacing
johnjasa May 6, 2026
9108d5d
Merge pull request #731 from elenya-grant/slc/storge_control_interfacing
johnjasa May 6, 2026
770e6e3
Merging
johnjasa May 7, 2026
f2e023b
Added control classifiers to all technologies
johnjasa May 7, 2026
a56a57f
updated baseclass methods and demand following controller
elenya-grant May 7, 2026
0f5e5e7
updated cost control strategies and cleaned up baseclass
elenya-grant May 7, 2026
916f369
Merge pull request #732 from johnjasa/marginal_costs
johnjasa May 7, 2026
494475f
Merge pull request #735 from elenya-grant/slc/clean_up_methods
johnjasa May 7, 2026
e8b0319
updated find_converter_tech method
elenya-grant May 7, 2026
8fd6a76
started adding logic for multi-commods
elenya-grant May 7, 2026
2432793
connected feedstocks
elenya-grant May 7, 2026
e565bc3
Merging
johnjasa May 7, 2026
4bbab17
removed control classifier from demand components
elenya-grant May 7, 2026
909af6d
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
johnjasa May 7, 2026
ae3b8d1
moved logic from compute to method in demand following
elenya-grant May 7, 2026
add6a4e
merged in upstream
elenya-grant May 7, 2026
0f7d6b9
updated find_converter_techs and get_upstream_techs_for_commodity
elenya-grant May 7, 2026
be846a0
bugfix
elenya-grant May 7, 2026
1f2e5cc
Ard control classifier
kbrunik May 7, 2026
8f77755
Updating for changes to slc_config
johnjasa May 7, 2026
aac36d4
Merging
johnjasa May 7, 2026
883c0b9
ard.
kbrunik May 7, 2026
66c655e
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
kbrunik May 7, 2026
b6b1415
test
kbrunik May 7, 2026
f46e7c8
updated _find_feedstock_techs to use self.feedstock_comps
elenya-grant May 7, 2026
b34bb91
updated some doc strings in slc baseclass
elenya-grant May 7, 2026
0caae7a
Merging
johnjasa May 8, 2026
4fb8990
docs wip
kbrunik May 8, 2026
31711d4
Minor refactor to demand following control
johnjasa May 8, 2026
db182b5
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
johnjasa May 8, 2026
9bae204
docs
kbrunik May 8, 2026
a50ba5a
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
kbrunik May 8, 2026
b04ece2
docs
kbrunik May 8, 2026
66e1153
Additional refactoring of demand following control
johnjasa May 8, 2026
df47e4f
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
johnjasa May 8, 2026
ebb9abb
Refactoring some SLC base methods
johnjasa May 8, 2026
b427be8
Added complex profit max example to test
johnjasa May 8, 2026
59b1676
updated location of cost_per_tech
elenya-grant May 8, 2026
3a20fcf
update SLC add method
johnjasa May 8, 2026
503c606
update SLC add method
johnjasa May 8, 2026
4deb91d
Refactoring some SLC base methods
johnjasa May 8, 2026
2b7fed5
Expanding SLC docstrings
johnjasa May 8, 2026
da11a52
refactored test_slc_controllers
elenya-grant May 8, 2026
92336b1
Merge remote-tracking branch 'h2i_upstream/system_level_control' into…
elenya-grant May 8, 2026
6eeac71
docs update
kbrunik May 10, 2026
9beec63
more docs
kbrunik May 11, 2026
f763302
updated no_battery example
elenya-grant May 11, 2026
12f0b11
cleaned up other slc examples
elenya-grant May 11, 2026
6af2397
removed SLC baseconfig since its unused
elenya-grant May 11, 2026
dee1925
updated docstring in baseclass
elenya-grant May 11, 2026
37be44e
docs added
kbrunik May 11, 2026
dc7bbf8
Merge branch 'system_level_control' of https://github.com/NREL/H2Inte…
kbrunik May 11, 2026
416dc5d
minor update to demand following and updated profast to handle zero cf
elenya-grant May 11, 2026
7deabec
added start of demand following docs
elenya-grant May 11, 2026
c8ecead
added draft of demand following docs
elenya-grant May 11, 2026
b6003fe
Adding to SLC docs
johnjasa May 12, 2026
2b4f835
small doc mods
kbrunik May 12, 2026
e8cf31f
minor update to doc page
elenya-grant May 12, 2026
654a008
merge ci.yml
elenya-grant May 12, 2026
0263a58
minor clarification in doc
elenya-grant May 12, 2026
85c8679
Reconfiguring the connection for varopex
johnjasa May 13, 2026
26b5e74
Merge branch 'develop' into system_level_control
johnjasa May 13, 2026
ecf4273
Shifting to five control classifiers
johnjasa May 14, 2026
4fbd901
small doc change
kbrunik May 14, 2026
4deb083
connected storage duration
elenya-grant May 14, 2026
ecec21f
Merge branch 'develop' into system_level_control
johnjasa May 19, 2026
8c968a4
added more subtests to test_slc_examples for the two single-commodity…
elenya-grant May 19, 2026
f08382c
Fixing example dir
johnjasa May 20, 2026
1d51984
fixed failing test
elenya-grant May 20, 2026
784e937
Checkpointing progress on all controllers for techs
johnjasa May 21, 2026
83577e1
Adding passthrough controller file
johnjasa May 22, 2026
8dbd7bd
Updating tests
johnjasa May 22, 2026
b2f13c0
Added comments to passthrough controller
johnjasa May 22, 2026
67c43b9
Merging
johnjasa May 22, 2026
dfe4cf4
Fixing import statements
johnjasa May 22, 2026
270b4d8
Fixing tests and examples
johnjasa May 22, 2026
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
name: Testing
on:
push:
branches:
- main
- develop
- system_level_control
pull_request:
branches:
- main
Expand Down
18 changes: 14 additions & 4 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,20 @@ parts:
- file: resource/tidal_resource
- caption: Control
chapters:
- file: control/control_overview
- file: control/open-loop_controllers
- file: control/pyomo_controllers
- file: control/controller_demonstrations
- file: control/system_level_control/system_level_control
sections:
- file: control/system_level_control/system_level_control_base
- file: control/system_level_control/control_classifier
- file: control/system_level_control/controllers
sections:
- file: control/system_level_control/slc_demand_following
- file: control/system_level_control/slc_profit_max
- file: control/system_level_control/slc_cost_min
- file: control/technology_level_control/technology_control_overview
sections:
- file: control/technology_level_control/open-loop_controllers
- file: control/technology_level_control/pyomo_controllers
- file: control/technology_level_control/controller_demonstrations
- caption: Demand
chapters:
- file: demand/demand_components
Expand Down
69 changes: 69 additions & 0 deletions docs/control/system_level_control/control_classifier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# System Level Control Technology Performance Classifiers

To enable a generic system level control framework we need to classify each technology based on how the model, that is included in H2I, can operate within the system.

```{note}
While in real life there are a lot of controllable parameters allowing for ramping production up or down for a particular technology (e.g., turbine yaw). The particular model in H2I might not be capable of simulating a modulated response based on an input signal.
These classifications are for how the models in H2I are implemented, **not** how the actual physical subsystem might operate.
This is a useful and necessary distinction that delineates different model capabilities clearly.
```

We have identified five key classifiers that are able to represent the different behaviors that we can expect from the models. Each performance model includes a parameter setting the classifier `_control_classifier`.

Classifier | Meaning | Example Technology Models
-- | -- | --
fixed | Always produces commodity and cannot be controlled or reduced; does not receive a set-point | classical nuclear
flexible | Produces based on resource; can only reduce (curtail) | wind, solar
dispatchable | Can modulate consumption/production within bounds; receives a commodity set-point | grid, electrolyzer, NG turbine
storage | Can modulate consumption/production within bounds while tracking SOC | battery, h2 storage, any storage
feedstock | Are not directly controlled, but useful for SLC to know about to make dispatch decisions | feedstocks

To add a classifier for a particular model it would look something like this in the class:
```{python}
_control_classifier = "flexible"
```

## Fixed
A fixed performance model represents anything that always produces at its rated capacity and cannot be controlled or reduced by the system level controller. The SLC reads the output from a fixed technology and subtracts it from the demand, but does not send a set-point back to the technology. A good example of this is a classical nuclear plant model — it produces a constant output that the rest of the system must accommodate.

## Flexible
A flexible performance model represents anything that can have the output reduced based on a given set point from the system level controller. A good example of this is the PVWatts PySAM solar plant in H2I, the performance of the system is based on the input solar resource. The solar performance does not change based on, for example, an updated set point to the tracking software, but we could limit the power output from the solar performance model based on a given demand set point. To simplify the implementation of applying this curtailment or reduction based on a set point we added a method, `apply_curtailment()` to the `PerformanceBaseClass`.

```{figure} figures/curtailable.png
:width: 70%
:align: center
```

### Apply curtailment based on set_point
Within the `compute()` method in the performance model you can apply the curtailment using the `apply_curtailment()` method.
```
self.apply_curtailment(outputs)
```
which, applies curtailment to `{commodity}_out` based on `{commodity}_set_point`. There is then `uncurtailed_{commodity}_out` and `{commodity}_out` as outputs from the performance model.

## Dispatchable
A dispatchable performance model represents anything that can receive a set point. Any model that has the "dispatchable" control classifier tag is able to receive a set point and change it's behavior based on that set point. There aren't additional special methods to handle this because it's internal to each performance model.

```{figure} figures/dispatchable.png
:width: 70%
:align: center
```

## Storage
Storage is a unique control classifier because it assumes that within the model that energy isn't created or destroyed (minus some efficiency losses). While it's technically "dispatchable" in that it can receive and change its performance based on a set point it's handling within H2I is unique because it's attached to storage performance models, which is handled differently than converter performance models. A converter model only has positive (or zero) `{commodity}_out`, whereas a storage model can have positive or negative `{commodity}_out`.

There are two types of cases for the storage control classifier:
1. **with a storage controller**
When the storage performance model is controlled with a storage-level controller (open-loop or feedback controlled), the system-level controller outputs combined demand, that is always positive to the storage-level controller. The demand is `{commodity}_in` from the technologies upstream of the storage that output the same commodity to the storage performance model and the `remaining_demand`.

2. **without a storage controller**
The system-level controller outputs set points to the storage performance model which can be considered charge (negative) and discharge (positive) commands (storage-level set points) to the storage performance model, directly.


```{figure} figures/storage.png
:width: 85%
:align: center
```

## Feedstock
Another category of control classifiers are feedstocks. The unique thing about feedstocks is that they are considered outside of the controllable system within H2I. While they can't be controlled it can be helpful for controllers to know how much feedstock is available within the system, hence their classification.
15 changes: 15 additions & 0 deletions docs/control/system_level_control/controllers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Control Strategies
There are several simple control strategies already implemented in the SLC paradigm. While fairly simplistic, they are meant to illustrate how information can be passed from different blocks/components (converters, storage, feedstocks, demand, etc.) and models (performance, cost, finance) to use within the SLC.

The current control strategies are:
1. [Demand Following](#slc-demand-following)
2. [Profit Maximization](#slc-profit-max)
3. [Cost Minimization](#slc-cost-min)

```{note}
The strategies currently implemented are experimental and will likely require further development for specific analyses.
```

All control strategies inherit `SystemLevelControlBase`, which is a base class that has common setup logic shared by all system-level control strategies.

See additional information, which is more developer focused, about the [`SystemLevelControlBase`](#slc-base).
72 changes: 72 additions & 0 deletions docs/control/system_level_control/slc_cost_min.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.18.1
kernelspec:
display_name: Python 3.11.13 ('h2i_env')
language: python
name: python3
---

(slc-cost-min)=
# Cost Minimization System Level Controller

The cost minimization controller, `CostMinimizationControl`, meets demand at minimum variable cost using merit-order dispatch.
Unlike the {ref}`demand following controller <slc-demand-following>`, which splits demand evenly across dispatchable technologies, this controller dispatches the cheapest technologies first.

## Dispatch Logic

The controller follows a three-step dispatch process:

1. **Curtailable technologies** run at their full rated capacity (assumed zero marginal cost). Their output is subtracted from the demand.
2. **Storage technologies** absorb any surplus (charging) or provide the deficit (discharging). Residual demand is split evenly across storage technologies producing the demanded commodity.
3. **Dispatchable technologies** are dispatched by cheapest marginal cost first, each up to its rated capacity, until the remaining demand is met.

## Marginal Cost Configuration

Marginal costs are specified per dispatchable technology in the `cost_per_tech` dictionary under `system_level_control.control_parameters` in the plant config. Each entry can be:

| Value | Description |
| --- | --- |
| Numeric (e.g. `0.05`) | Constant marginal cost in `$/(commodity_unit*h)` |
| `"buy_price"` | Uses the technology's configured purchase price |
| `"VarOpEx"` | Derives marginal cost from the technology's variable operating expenditure divided by total production |
| `"feedstock"` | Sums upstream feedstock `VarOpEx` values and divides by the technology's total production |

```{note}
The dispatch order is determined by sorting dispatchable technologies by their **mean** marginal cost across all timesteps (cheapest first).
```

### Example Configuration

```yaml
system_level_control:
control_strategy: CostMinimizationControl
control_parameters:
cost_per_tech:
natural_gas_plant: feedstock
```

## Inputs and Outputs

In addition to the standard inputs inherited from `SystemLevelControlBase`, the cost minimization controller adds marginal cost inputs based on the `cost_per_tech` configuration (see above).

The base inputs for technologies classified as `curtailable`, `dispatchable`, and `storage` are:

- `f"{tech_name}_{tech_output_commodity}_out"`
- `f"{tech_name}_rated_{tech_output_commodity}_production"`

The outputs for `curtailable`, `dispatchable`, or `storage` technologies *without* a storage controller are:
- `f"{tech_name}_{tech_output_commodity}_set_point"`

The outputs for `storage` technologies *with* a storage controller are:
- `f"{tech_name}_{tech_output_commodity}_demand"`

## Limitations

- Greedy dispatch: The merit-order approach is greedy - it does not look ahead across timesteps to optimize total cost over the simulation horizon.
- Even splitting across storage: Residual demand is split evenly across storage technologies regardless of capacity or state of charge.
- Demand is always met: Unlike the {ref}`profit maximization controller <slc-profit-max>`, this controller always attempts to meet demand regardless of cost.
108 changes: 108 additions & 0 deletions docs/control/system_level_control/slc_demand_following.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
jupytext:
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.18.1
kernelspec:
display_name: Python 3.11.13 ('h2i_env')
language: python
name: python3
---

(slc-demand-following)=
# Demand Following System Level Controller

The demand following controller, `DemandFollowingControl`, aims to fully meet the demand and does not have any inputs related to cost.

The N2 diagram below shows an example system using the demand following controller with wind, natural gas, and battery storage technologies.

```{code-cell} ipython3
:tags: [remove-input]

from h2integrate.core.h2integrate_model import H2IntegrateModel
import openmdao.api as om
import os

import html
from pathlib import Path
from h2integrate import EXAMPLE_DIR
from IPython.display import HTML, display

os.chdir(EXAMPLE_DIR / "35_system_level_control/battery_with_controller/")

h2i_model = H2IntegrateModel("wind_ng_demand.yaml")
h2i_model.setup()

om.n2(
h2i_model.prob,
outfile="h2i_n2.html",
display_in_notebook=False,
show_browser=False,
)

n2_html = "h2i_n2.html"
n2_srcdoc = html.escape(Path(n2_html).read_text(encoding="utf-8"))
display(
HTML(
f'<div style="width:100%; height:600px; overflow:auto; margin:0; padding:0; border:0;">'
f'<iframe srcdoc="{n2_srcdoc}" '
'style="display:block; width:200%; height:600px; border:0; margin:0; padding:0; background:transparent;" '
'loading="lazy"></iframe>'
'</div>'
)
)
```
## Dispatch Logic

The demand is satisfied in a fixed three-step priority order, and each step's shortfall or surplus is passed to the next:

1. **Curtailable techs** run at their full rated capacity. Their total output is subtracted from the demand, which may drive the residual demand negative (surplus).

2. **Storage techs** receive the residual demand (which may be positive or negative). When demand is positive the storage is commanded to discharge; when negative it is commanded to charge. If multiple storage techs produce the demanded commodity, the residual demand is
split **evenly** across them (each receives ``demand / n_storage``).

3. **Dispatchable techs** cover any remaining positive demand after storage. The remaining demand (floored at zero) is split **evenly** across all dispatchable techs that produce the demanded commodity (each receives ``remaining_demand / n_dispatchable``).

### Example Configuration

```yaml
system_level_control:
control_strategy: DemandFollowingControl
solver_options: # solver options for resolving feedback
solver_name: gauss_seidel
max_iter: 20
convergence_tolerance: 1.0e-6
```

## Inputs and Outputs

The inputs for technologies classified as `curtailable`, `dispatchable`, and `storage` are:

- `f"{tech_name}_{tech_output_commodity}_out"`
- `f"{tech_name}_rated_{tech_output_commodity}_production"`

The inputs for technologies classified as `feedstock` are:
- `f"{tech_name}_{commodity}_out"`


The outputs for technologies classified as `curtailable`, `dispatchable`, or `storage` and *without a storage controller* are:
- `f"{tech_name}_{tech_output_commodity}_set_point"`

The outputs for technologies classified as `storage` that *have a storage controller* are:
- `f"{tech_name}_{tech_output_commodity}_demand"`

## Systems with Heterogeneous Commodities

The `DemandFollowingControl` controller can be used in hybrid systems where technologies produce different commodities.
For example, in a system where an electrolyzer produces hydrogen and the demand commodity is hydrogen, the controller can set the electricity-generating *curtailable* technologies' set-points to meet the hydrogen demand.

This framework provides a starting point for hybrid energy system control but is intended to be extended with more sophisticated strategies for complex multi-commodity systems.

## Limitations

- No cost awareness: The controller dispatches technologies purely to meet demand without considering operational costs, commodity prices, or economic optimization.
- Even splitting across storage: When multiple storage technologies produce the demanded commodity, the residual demand is divided evenly among them (`demand / n_storage`), regardless of differences in capacity, state of charge, or efficiency.
- Even splitting across dispatchable technologies: Similarly, any remaining demand after storage dispatch is split evenly across all dispatchable technologies (`remaining_demand / n_dispatchable`), without accounting for marginal costs or capacity constraints.
- Fixed priority order: The dispatch order (curtailable → storage → dispatchable) is fixed in the current implementation.
Loading
Loading