Skip to content

Commit

Permalink
Add relaxation.
Browse files Browse the repository at this point in the history
Signed-off-by: Victor Garcia Reolid <victor@seita.nl>
  • Loading branch information
victorgarcia98 committed Jun 12, 2024
1 parent 8972dae commit 4279e54
Show file tree
Hide file tree
Showing 4 changed files with 352 additions and 5 deletions.
44 changes: 39 additions & 5 deletions flexmeasures/data/models/planning/linear_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def device_scheduler( # noqa C901
commitment_downwards_deviation_price: list[pd.Series] | list[float],
commitment_upwards_deviation_price: list[pd.Series] | list[float],
initial_stock: float = 0,
relaxed: bool = False,
relaxation_cost: float = 20000,
) -> tuple[list[pd.Series], float, SolverResults, ConcreteModel]:
"""This generic device scheduler is able to handle an EMS with multiple devices,
with various types of constraints on the EMS level and on the device level,
Expand Down Expand Up @@ -273,6 +275,9 @@ def device_stock_delta(m, d, j):
model.c, model.j, domain=NonNegativeReals, initialize=0
)

model.ems_power_slack_upper = Var(domain=NonNegativeReals, initialize=0)
model.ems_power_slack_lower = Var(domain=NonNegativeReals, initialize=0)

# Add constraints as a tuple of (lower bound, value, upper bound)
def device_bounds(m, d, j):
"""Apply conversion efficiencies to conversion from flow to stock change and vice versa,
Expand Down Expand Up @@ -328,8 +333,26 @@ def device_down_derivative_sign(m, d, j):
"""Derivative down if sign points down, derivative not down if sign points up."""
return -m.device_power_down[d, j] <= M * (1 - m.device_power_sign[d, j])

def ems_derivative_bounds(m, j):
return m.ems_derivative_min[j], sum(m.ems_power[:, j]), m.ems_derivative_max[j]
def ems_derivative_lower_bound(m, j):

if relaxed:
return (
m.ems_derivative_min[j],
sum(m.ems_power[:, j]) + m.ems_power_slack_lower,
None,
)
else:
return m.ems_derivative_min[j], sum(m.ems_power[:, j]), None

def ems_derivative_upper_bound(m, j):
if relaxed:
return (
None,
sum(m.ems_power[:, j]) - m.ems_power_slack_upper,
m.ems_derivative_max[j],
)
else:
return None, sum(m.ems_power[:, j]), m.ems_derivative_max[j]

def ems_flow_commitment_equalities(m, j):
"""Couple EMS flows (sum over devices) to commitments."""
Expand Down Expand Up @@ -366,7 +389,9 @@ def device_derivative_equalities(m, d, j):
model.device_power_down_sign = Constraint(
model.d, model.j, rule=device_down_derivative_sign
)
model.ems_power_bounds = Constraint(model.j, rule=ems_derivative_bounds)
model.ems_power_upper_bound = Constraint(model.j, rule=ems_derivative_upper_bound)
model.ems_power_lower_bounds = Constraint(model.j, rule=ems_derivative_lower_bound)

model.ems_power_commitment_equalities = Constraint(
model.j, rule=ems_flow_commitment_equalities
)
Expand All @@ -377,10 +402,19 @@ def device_derivative_equalities(m, d, j):
# Add objective
def cost_function(m):
costs = 0
for c in m.c:
for j in m.j:
for j in m.j:
for c in m.c:
costs += m.commitment_downwards_deviation[c, j] * m.down_price[c, j]
costs += m.commitment_upwards_deviation[c, j] * m.up_price[c, j]

if relaxed:
costs += (
m.ems_power_slack_upper * relaxation_cost
) # TODO: compute this value based on input dat
costs += (
m.ems_power_slack_lower * relaxation_cost
) # TODO: compute this value based on input dat

return costs

model.costs = Objective(rule=cost_function, sense=minimize)
Expand Down
1 change: 1 addition & 0 deletions flexmeasures/data/models/planning/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ def compute(self, skip_validation: bool = False) -> SchedulerOutputType:
commitment_downwards_deviation_price,
commitment_upwards_deviation_price,
initial_stock=soc_at_start * (timedelta(hours=1) / resolution),
relaxed=self.flex_model.get("relaxed", False),
)
if scheduler_results.solver.termination_condition == "infeasible":
raise InfeasibleProblemException()
Expand Down
2 changes: 2 additions & 0 deletions flexmeasures/data/schemas/scheduling/storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class StorageFlexModelSchema(Schema):
QuantityOrSensor("MW"), data_key="soc-usage", required=False
)

relaxed = fields.Bool(data_key="relaxed", required=False, default=False)

def __init__(self, start: datetime, sensor: Sensor, *args, **kwargs):
"""Pass the schedule's start, so we can use it to validate soc-target datetimes."""
self.start = start
Expand Down
Loading

0 comments on commit 4279e54

Please sign in to comment.