This reference sheet captures the core real-time inputs and the optimizer model changes required when restrictions arrive as a stream (for example from Kafka).
t.t.t.t.t.t.t.class RealtimeConstraintSnapshot:
def __init__(self, horizon_hours: int):
self.max_charge_mw = [p_max] * horizon_hours
self.max_discharge_mw = [p_max] * horizon_hours
self.soc_min_pct = [soc_min] * horizon_hours
self.soc_max_pct = [soc_max] * horizon_hours
self.reserved_energy_mwh = [0.0] * horizon_hours
def apply_restriction(self, restriction):
for t in range(restriction.relative_start, restriction.relative_end):
self.max_charge_mw[t] = min(self.max_charge_mw[t], restriction.max_charge_mw)
self.max_discharge_mw[t] = min(self.max_discharge_mw[t], restriction.max_discharge_mw)
self.soc_min_pct[t] = max(self.soc_min_pct[t], restriction.soc_min_pct)
self.soc_max_pct[t] = min(self.soc_max_pct[t], restriction.soc_max_pct)
self.reserved_energy_mwh[t] = max(self.reserved_energy_mwh[t], restriction.reserved_energy_mwh)
model.p_charge_max = pyo.Param(model.T, initialize=p_charge_max, mutable=True)
model.p_discharge_max = pyo.Param(model.T, initialize=p_discharge_max, mutable=True)
model.soc_min_pct = pyo.Param(model.T, initialize=soc_min_pct, mutable=True)
model.soc_max_pct = pyo.Param(model.T, initialize=soc_max_pct, mutable=True)
model.reserved_energy_mwh = pyo.Param(model.T, initialize=reserved_energy_mwh, mutable=True)
model.p_c = pyo.Var(model.T, bounds=(0, p.p_max))
model.p_d = pyo.Var(model.T, bounds=(0, p.p_max))
model.soc = pyo.Var(model.T, bounds=(0, p.e_max))
model.charge_limit = pyo.Constraint(model.T,
rule=lambda m, t: m.p_c[t] <= m.p_charge_max[t])
model.discharge_limit = pyo.Constraint(model.T,
rule=lambda m, t: m.p_d[t] <= m.p_discharge_max[t])
model.soc_min_con = pyo.Constraint(model.T,
rule=lambda m, t: m.soc[t] >= m.soc_min_pct[t] * p.e_max + m.reserved_energy_mwh[t])
model.soc_max_con = pyo.Constraint(model.T,
rule=lambda m, t: m.soc[t] <= m.soc_max_pct[t] * p.e_max)
p_charge[t], p_discharge[t], and soc[t].Rechtliches: Impressum