Skip to content

feat: Split flex-context settings by commodity for dynamic capacity scheduling#2172

Open
Ahmad-Wahid wants to merge 3 commits into
feat/multi-feed-stockfrom
dev/split-flexcontext-by-commodity
Open

feat: Split flex-context settings by commodity for dynamic capacity scheduling#2172
Ahmad-Wahid wants to merge 3 commits into
feat/multi-feed-stockfrom
dev/split-flexcontext-by-commodity

Conversation

@Ahmad-Wahid
Copy link
Copy Markdown
Contributor

Description

This PR updates the dynamic consumption capacity scheduling test to use split, commodity-specific flex-context settings for electricity and gas. It adds dynamic electricity and gas price data so the scheduler can prefer the electric heater when electricity is cheaper and the gas boiler when gas is cheaper, while ensuring that the dynamic electricity site consumption capacity is only applied to electricity devices and does not incorrectly constrain gas devices.

  • Added changelog item in documentation/changelog.rst

Look & Feel

flex_context = {
        "commodities": [
            {
                "commodity": "electricity",
                "consumption-price": {
                    "sensor": consumption_price.id,
                },
                "production-price": {
                    "sensor": consumption_price.id,
                },
                "site-power-capacity": "1900 kW",
                "site-consumption-capacity": {
                    "sensor": dynamic_consumption_capacity.id,
                },
                "site-production-capacity": "100 kW",
                "site-consumption-breach-price": "100000 EUR/kW",
                "site-production-breach-price": "100000 EUR/kW",
            },
            {
                "commodity": "gas",
                "consumption-price": {
                    "sensor": gas_price.id,
                },
                "production-price": {
                    "sensor": gas_price.id,
                },
                # No electricity dynamic capacity here.
                "site-consumption-capacity": "100000 kW",
            },
        ],
        "relax-constraints": True,
        "inflexible-device-sensors": [building_raw_power.id],
    }

...

How to test

pytest -k test_simulation_with_dynamic_consumption_capacity

...

Further Improvements

...

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

… scheduler

Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
…capacity scheduling test

Signed-off-by: Ahmad-Wahid <ahmedwahid16101@gmail.com>
@Ahmad-Wahid Ahmad-Wahid requested a review from Flix6x May 14, 2026 12:17
@Ahmad-Wahid Ahmad-Wahid self-assigned this May 14, 2026
Copy link
Copy Markdown
Contributor

@Flix6x Flix6x left a comment

Choose a reason for hiding this comment

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

Quick review. Also please triage the failing test suite.

Comment on lines +98 to +137
# Backwards-compatible electricity defaults from old top-level fields.
if "electricity" not in commodity_contexts:
commodity_contexts["electricity"] = {
"commodity": "electricity",
"consumption_price": self.flex_context.get(
"consumption_price",
self.flex_context.get("consumption_price_sensor"),
),
"production_price": self.flex_context.get(
"production_price",
self.flex_context.get("production_price_sensor"),
),
"ems_power_capacity_in_mw": self.flex_context.get(
"ems_power_capacity_in_mw"
),
"ems_consumption_capacity_in_mw": self.flex_context.get(
"ems_consumption_capacity_in_mw"
),
"ems_production_capacity_in_mw": self.flex_context.get(
"ems_production_capacity_in_mw"
),
"ems_consumption_breach_price": self.flex_context.get(
"ems_consumption_breach_price"
),
"ems_production_breach_price": self.flex_context.get(
"ems_production_breach_price"
),
"ems_peak_consumption_in_mw": self.flex_context.get(
"ems_peak_consumption_in_mw"
),
"ems_peak_consumption_price": self.flex_context.get(
"ems_peak_consumption_price"
),
"ems_peak_production_in_mw": self.flex_context.get(
"ems_peak_production_in_mw"
),
"ems_peak_production_price": self.flex_context.get(
"ems_peak_production_price"
),
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's shorten this, by looping over all flex-context fields except the ones you wish to exclude. The commitments and inflexible-device-sensors, for instance, are also about electricity devices, and they are missed right now.

I think the only ones you want to exclude are the gas ones and the constraint relaxations.

class CommodityFlexContextSchema(Schema):
commodity = fields.Str(
required=True,
validate=validate.OneOf(["electricity", "gas"]),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I want to let go of this constraint. I suggest moving this list to

metadata={
    "description": "<please suggest something>",
    "examples": ["electricity", "gas"],
}

Comment on lines +149 to +224
consumption_price = VariableQuantityField(
"/MWh",
required=False,
data_key="consumption-price",
return_magnitude=False,
)

production_price = VariableQuantityField(
"/MWh",
required=False,
data_key="production-price",
return_magnitude=False,
)

ems_power_capacity_in_mw = VariableQuantityField(
"MW",
required=False,
data_key="site-power-capacity",
value_validator=validate.Range(min=0),
)

ems_consumption_capacity_in_mw = VariableQuantityField(
"MW",
required=False,
data_key="site-consumption-capacity",
value_validator=validate.Range(min=0),
)

ems_production_capacity_in_mw = VariableQuantityField(
"MW",
required=False,
data_key="site-production-capacity",
value_validator=validate.Range(min=0),
)

ems_consumption_breach_price = VariableQuantityField(
"/MW",
required=False,
data_key="site-consumption-breach-price",
value_validator=validate.Range(min=0),
)

ems_production_breach_price = VariableQuantityField(
"/MW",
required=False,
data_key="site-production-breach-price",
value_validator=validate.Range(min=0),
)

ems_peak_consumption_in_mw = VariableQuantityField(
"MW",
required=False,
data_key="site-peak-consumption",
value_validator=validate.Range(min=0),
)

ems_peak_consumption_price = VariableQuantityField(
"/MW",
required=False,
data_key="site-peak-consumption-price",
value_validator=validate.Range(min=0),
)

ems_peak_production_in_mw = VariableQuantityField(
"MW",
required=False,
data_key="site-peak-production",
value_validator=validate.Range(min=0),
)

ems_peak_production_price = VariableQuantityField(
"/MW",
required=False,
data_key="site-peak-production-price",
value_validator=validate.Range(min=0),
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should refactor this so that field definitions are reused. So along the lines of:

class SharedSchema(Schema):
    ...  # all shared fields

class CommodityFlexContextSchema(SharedSchema):
    commodity = fields.Str()

class FlexContextSchema(SharedSchema):
    commodity_contexts = fields.Nested(
        CommodityFlexContextSchema,
    )

We should see the effect of this in the openapi-specs.json right away: i.e. better field documentation.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants