Skip to content

Feat: Support shared storage (multi‑feed stock)#2001

Draft
Ahmad-Wahid wants to merge 9 commits intofeat/multi-commodityfrom
feat/multi-feed-stock
Draft

Feat: Support shared storage (multi‑feed stock)#2001
Ahmad-Wahid wants to merge 9 commits intofeat/multi-commodityfrom
feat/multi-feed-stock

Conversation

@Ahmad-Wahid
Copy link
Contributor

@Ahmad-Wahid Ahmad-Wahid commented Mar 5, 2026

Description

This PR adds support for shared storage stocks in the StorageScheduler.

Multiple devices can now reference the same storage by specifying a stock-id in their flex‑model. Devices with the same stock-id share a single state-of-charge (SOC) trajectory.

If stock-id is not provided, the scheduler behaves exactly as before (each device has its own SOC).

Example

flex_model = [
  {"sensor": s1.id, "stock-id": "shared", "soc-at-start": 20, "soc-max": 140},
  {"sensor": s2.id, "stock-id": "shared", "soc-at-start": 20, "soc-max": 140},
]

Both devices now charge/discharge the same storage.

Todos:

  • spec how we would encode the shared storage per device in the flex-model
  • extend flex-model schema
  • add support for multi feed stock
  • extend scheduling.rst
  • extend tutorial

How to test

pytest -k test_two_devices_shared_stock

Expected:

  • two storage_schedules
  • one state_of_charge schedule
  • SOC evolves according to the combined power flows

Related Items

Sign-off

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on code under GPL or other license that is incompatible with FlexMeasures

Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
…multi-feed-stock

# Conflicts:
#	flexmeasures/data/models/planning/tests/test_commitments.py
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
@Ahmad-Wahid Ahmad-Wahid self-assigned this Mar 5, 2026
@Ahmad-Wahid
Copy link
Contributor Author

Ahmad-Wahid commented Mar 5, 2026

In the test case, we are scheduling b1 battery, and both batteries are storing energy in soc1 with soc max at 140 kWh. Although, each battery has soc-max is 100 kWh. Should we constraint the combined storage energy to 100 kWh or is fine as it is right now?

@Ahmad-Wahid
Copy link
Contributor Author

Currently, the docstring is not expected as the results we have. I will update it once I understand the issue.

@Flix6x

@Ahmad-Wahid
Copy link
Contributor Author

@Flix6x
Copy link
Contributor

Flix6x commented Mar 5, 2026

Just from reading the PR description (very helpful, thank you) and your comments, I had the idea to use the "state-of-charge" field in place of a new "stock-id" field. Some advantages of that:

  • No need for a new field.
  • We force the user to create a state-of-charge sensor if they want to use the multi-feed stock feature, which I feel will make it easier for them to interpret the schedules, because they'll then also get to see the state-of-charge schedule in the UI as it will be recorded on the sensor.
  • We then have an actual sensor representing the storage, so it makes sense to move the soc-min/max info there, so we can define it once instead of once per feeder.

So, for instance:

flex_model = [
  {"sensor": s1.id, "state-of-charge": soc_sensor.id},
  {"sensor": s2.id, "state-of-charge": soc_sensor.id},
  {"sensor": soc_sensor.id, "soc-at-start": 20, "soc-max": 140},
]

For discussion. Now I'll read the code.


def test_two_devices_shared_stock(app, db):
"""
Test scheduling two batteries sharing a single shared stock.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The concept of two batteries sharing a single shared stock is lost on me. I would describe the battery itself as representing the stock, and then having two feeders connected to it, for instance a treadmill and a bicycle trainer, which can both charge the battery.

schedules = scheduler.compute(skip_validation=True)

# Extract schedules by type
storage_schedules = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The term "storage schedule", which is also used in the StorageScheduler, has become misleading at this point (of our years-long development). Maybe "feeder schedule" is more appropriate. Although that would only fit devices that increase the SoC. Maybe "actuator schedule" or "flow schedule".

In any case, we should make a clearer distinction now between:

  1. the flow schedule (currently still named storage_schedule in the code)
  2. the stock schedule (currently still named soc_schedule in the code)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants