Skip to content

odys.optimization.power_balance

The power balance: at every scenario and step, the power injected into the bus adds up to zero. Every entity type contributes its Formulation.power_injection(); charging returns none, since the EV formulation already counts the charging power.

The balance is written out as PB-1 on the Power balance formulation page.

The power balance: at every scenario and timestep, the net power into the bus is zero.

PowerBalance

Bases: ConstraintGroup

Builds the power balance from every entity type's net power injection.

Every formulation contributes its power_injection(), in FORMULATIONS order; formulations outside the balance (charging) return None and are skipped.

Source code in src/odys/optimization/power_balance.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class PowerBalance(ConstraintGroup):
    """Builds the power balance from every entity type's net power injection.

    Every formulation contributes its `power_injection()`, in `FORMULATIONS` order;
    formulations outside the balance (charging) return None and are skipped.
    """

    def __init__(self, formulations: Sequence[Formulation]) -> None:
        """Initialize with the formulations of the problem, whose variables are already added."""
        self.formulations = formulations

    @constraint
    def _get_power_balance_constraint(self) -> ModelConstraint:
        """Net power into the bus equals zero: supply equals demand."""
        variable_injections: list[linopy.LinearExpression] = []
        fixed_injections: list[xr.DataArray] = []
        for formulation in self.formulations:
            match injection := formulation.power_injection():
                case linopy.LinearExpression():
                    variable_injections.append(injection)
                case xr.DataArray():
                    fixed_injections.append(injection)
                case None:
                    pass
                case _:
                    assert_never(injection)
        if not variable_injections:
            msg = "The power balance has no decision variable to balance."
            raise OdysError(msg)
        net_injection: linopy.LinearExpression = reduce(add, variable_injections)
        if fixed_injections:
            net_injection += reduce(add, fixed_injections)
        return ModelConstraint(
            name="power_balance_constraint",
            constraint=net_injection.to_constraint("=", 0),
        )

__init__(formulations)

Initialize with the formulations of the problem, whose variables are already added.

Source code in src/odys/optimization/power_balance.py
24
25
26
def __init__(self, formulations: Sequence[Formulation]) -> None:
    """Initialize with the formulations of the problem, whose variables are already added."""
    self.formulations = formulations