Skip to content
Snippets Groups Projects
Commit 093dd504 authored by Pedro L. Magalhães's avatar Pedro L. Magalhães
Browse files

Added support for convex and nonconvex price functions using the lambda...

Added support for convex and nonconvex price functions using the lambda formulation, for now only using blocks. Tests were slightly adjusted too.
parent 9d5156f4
No related branches found
No related tags found
1 merge request!7Added support for convex price functions using the delta formulation and...
...@@ -26,11 +26,6 @@ def price_lambda_block( ...@@ -26,11 +26,6 @@ def price_lambda_block(
# set of price segments # set of price segments
b.set_S = pyo.Set() b.set_S = pyo.Set()
# TODO: introduce a set of price segments for non-convex tariffs
# def init_set_S_nonconvex(b, s):
# return (s for s in b.set_S if b.param_price_function_is_convex)
# b.set_S_nonconvex = pyo.Set(within=b.set_S, initialize=init_set_S_nonconvex)
# ********************************************************************* # *********************************************************************
# ********************************************************************* # *********************************************************************
...@@ -53,66 +48,88 @@ def price_lambda_block( ...@@ -53,66 +48,88 @@ def price_lambda_block(
# ********************************************************************* # *********************************************************************
# ********************************************************************* # *********************************************************************
# TODO: consider replacing None in the bounds with inf in the parameter # set of points
b.set_P = pyo.Set(initialize=[i for i in range(len(b.set_S)+1)])
# import and export flows # set of x points
def bounds_var_trans_flows_s(b, s): def init_param_x_p(b, p):
if s in b.param_v_max_s: return 0 if p == 0 else sum(b.param_v_max_s[i] for i in range(p))
# predefined finite capacity b.param_x_p = pyo.Param(
return (0, b.param_v_max_s[s]) b.set_P,
else:
# infinite capacity
return (0, None)
b.var_trans_flows_s = pyo.Var(
b.set_S,
within=pyo.NonNegativeReals, within=pyo.NonNegativeReals,
bounds=bounds_var_trans_flows_s initialize=init_param_x_p
) )
# import and export flows # set of y points
def bounds_var_trans_flows_s(b, s): def init_param_y_p(b, p):
if s in b.param_v_max_s: return 0 if p == 0 else (b.param_x_p[p]-b.param_x_p[p-1])*b.param_p_s[p-1]+b.param_y_p[p-1]
# predefined finite capacity # sum(b.param_p_s[i] for i in range(p+1))
return (0, b.param_v_max_s[s]) b.param_y_p = pyo.Param(
else: b.set_P,
# infinite capacity
return (0, None)
b.var_trans_flows_s = pyo.Var(
b.set_S,
within=pyo.NonNegativeReals, within=pyo.NonNegativeReals,
bounds=bounds_var_trans_flows_s initialize=init_param_y_p
) )
# interpoint weights
b.var_weights_p = pyo.Var(b.set_P, within=pyo.UnitInterval)
# TODO: consider replacing None in the bounds with inf in the parameter
# transshipment flows
def bounds_var_trans_flows(b):
try:
return (0, sum(b.param_v_max_s[s] for s in b.set_S))
except Exception:
return (0, None)
b.var_trans_flows = pyo.Var(bounds=bounds_var_trans_flows)
# ********************************************************************* # *********************************************************************
# ********************************************************************* # *********************************************************************
# import flow costs and export flow revenues def rule_constr_stick_to_line(b):
def rule_constr_trans_monetary_flows(b): return sum(b.var_weights_p[p] for p in b.set_P) == 1
b.constr_stick_to_line = pyo.Constraint(rule=rule_constr_stick_to_line)
# *********************************************************************
# *********************************************************************
# import flow costs and export flow revenues (y equation)
def rule_constr_y_equation(b):
if (g,l) in b.parent_block().set_GL_imp: if (g,l) in b.parent_block().set_GL_imp:
return ( return (
sum(b.var_trans_flows_s[s]*b.param_p_s[s] sum(b.var_weights_p[p]*b.param_y_p[p] for p in b.set_P)
for s in b.set_S)
== b.parent_block().var_ifc_glqpk[(g,l,q,p,k)] == b.parent_block().var_ifc_glqpk[(g,l,q,p,k)]
) )
else: else:
return ( return (
sum(b.var_trans_flows_s[s]*b.param_p_s[s] sum(b.var_weights_p[p]*b.param_y_p[p] for p in b.set_P)
for s in b.set_S)
== b.parent_block().var_efr_glqpk[(g,l,q,p,k)] == b.parent_block().var_efr_glqpk[(g,l,q,p,k)]
) )
b.constr_trans_monetary_flows = pyo.Constraint( b.constr_y_equation = pyo.Constraint(rule=rule_constr_y_equation)
rule=rule_constr_trans_monetary_flows
# imported and exported flows (x equation)
def rule_constr_x_equation(b):
if (g,l) in b.parent_block().set_GL_imp:
return (
sum(b.var_weights_p[p]*b.param_x_p[p] for p in b.set_P)
== b.var_trans_flows
)
else:
return (
sum(b.var_weights_p[p]*b.param_x_p[p] for p in b.set_P)
== b.var_trans_flows
) )
b.constr_x_equation = pyo.Constraint(rule=rule_constr_x_equation)
# imported and exported flows # imported and exported flows (system equation)
def rule_constr_trans_flows(b): def rule_constr_sys_equation(b):
if (g,l) in b.parent_block().set_GL_imp: if (g,l) in b.parent_block().set_GL_imp:
return sum( return sum(
b.parent_block().var_v_glljqk[(g,l,l_star,j,q,k)] b.parent_block().var_v_glljqk[(g,l,l_star,j,q,k)]
for l_star in b.parent_block().set_L[g] for l_star in b.parent_block().set_L[g]
if l_star not in b.parent_block().set_L_imp[g] if l_star not in b.parent_block().set_L_imp[g]
for j in b.parent_block().set_J[(g,l,l_star)] # only directed arcs for j in b.parent_block().set_J[(g,l,l_star)] # only directed arcs
) == sum(b.var_trans_flows_s[s] for s in b.set_S) ) == b.var_trans_flows
else: else:
return sum( return sum(
b.parent_block().var_v_glljqk[(g,l_star,l,j,q,k)] b.parent_block().var_v_glljqk[(g,l_star,l,j,q,k)]
...@@ -120,8 +137,8 @@ def price_lambda_block( ...@@ -120,8 +137,8 @@ def price_lambda_block(
for l_star in b.parent_block().set_L[g] for l_star in b.parent_block().set_L[g]
if l_star not in b.parent_block().set_L_exp[g] if l_star not in b.parent_block().set_L_exp[g]
for j in b.parent_block().set_J[(g,l_star,l)] # only directed arcs for j in b.parent_block().set_J[(g,l_star,l)] # only directed arcs
) == sum(b.var_trans_flows_s[s] for s in b.set_S) ) == b.var_trans_flows
b.constr_trans_flows = pyo.Constraint(rule=rule_constr_trans_flows) b.constr_sys_equation = pyo.Constraint(rule=rule_constr_sys_equation)
# ********************************************************************* # *********************************************************************
# ********************************************************************* # *********************************************************************
...@@ -129,52 +146,10 @@ def price_lambda_block( ...@@ -129,52 +146,10 @@ def price_lambda_block(
# non-convex price functions # non-convex price functions
if not b.param_price_function_is_convex: if not b.param_price_function_is_convex:
# delta variables # declare SOS2
b.var_active_segment_s = pyo.Var(b.set_S, within=pyo.Binary) def rule_constr_sos2_weights(b):
return [b.var_weights_p[p] for p in b.set_P]
# segments must be empty if the respective delta variable is zero b.constr_sos2_weights = pyo.SOSConstraint(rule=rule_constr_sos2_weights, sos=2)
def rule_constr_empty_segment_if_delta_zero(b, s):
if len(b.set_S) == 1 or b.param_price_function_is_convex:
# single segment, skip
# convex, skip
return pyo.Constraint.Skip
return (
b.var_trans_flows_s[s] <=
b.param_v_max_s[s]*b.var_active_segment_s[s]
)
b.constr_empty_segment_if_delta_zero = pyo.Constraint(
b.set_S, rule=rule_constr_empty_segment_if_delta_zero
)
# if delta var is one, previous ones must be one too
# if delta var is zero, the next ones must also be zero
def rule_constr_delta_summing_logic(b, s):
if s == len(b.set_S)-1 or b.param_price_function_is_convex:
# last segment, skip
# convex, skip
return pyo.Constraint.Skip
return (
b.var_active_segment_s[s] >=
b.var_active_segment_s[s+1]
)
b.constr_delta_summing_logic = pyo.Constraint(
b.set_S, rule=rule_constr_delta_summing_logic
)
# if a segment is not completely used, the next ones must remain empty
def rule_constr_fill_up_segment_before_next(b, s):
if s == len(b.set_S)-1 or b.param_price_function_is_convex:
# last segment, skip
# convex, skip
return pyo.Constraint.Skip
return (
b.var_trans_flows_s[s] >=
b.var_active_segment_s[s+1]*
b.param_v_max_s[s]
)
b.constr_fill_up_segment_before_next = pyo.Constraint(
b.set_S, rule=rule_constr_fill_up_segment_before_next
)
# ********************************************************************* # *********************************************************************
# ********************************************************************* # *********************************************************************
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import pyomo.environ as pyo import pyomo.environ as pyo
from .other import price_other_block, price_other_no_block from .other import price_other_block, price_other_no_block
from .delta import price_delta_block, price_delta_no_block from .delta import price_delta_block, price_delta_no_block
from .lambda_ import price_lambda_block, price_lambda_no_block
# ***************************************************************************** # *****************************************************************************
# ***************************************************************************** # *****************************************************************************
...@@ -29,7 +30,7 @@ def add_price_functions( ...@@ -29,7 +30,7 @@ def add_price_functions(
if use_blocks: if use_blocks:
# with blocks # with blocks
if node_price_model == NODE_PRICE_LAMBDA: if node_price_model == NODE_PRICE_LAMBDA:
raise NotImplementedError price_lambda_block(model, **kwargs)
elif node_price_model == NODE_PRICE_DELTA: elif node_price_model == NODE_PRICE_DELTA:
price_delta_block(model, **kwargs) price_delta_block(model, **kwargs)
else: else:
...@@ -37,7 +38,7 @@ def add_price_functions( ...@@ -37,7 +38,7 @@ def add_price_functions(
else: else:
# without blocks # without blocks
if node_price_model == NODE_PRICE_LAMBDA: if node_price_model == NODE_PRICE_LAMBDA:
raise NotImplementedError price_lambda_no_block(model, **kwargs)
elif node_price_model == NODE_PRICE_DELTA: elif node_price_model == NODE_PRICE_DELTA:
price_delta_no_block(model, **kwargs) price_delta_no_block(model, **kwargs)
else: else:
......
...@@ -98,7 +98,7 @@ def statistics(ipp: InfrastructurePlanningProblem, ...@@ -98,7 +98,7 @@ def statistics(ipp: InfrastructurePlanningProblem,
) )
if prices_in_block: if prices_in_block:
# imports # imports
if ipp.node_price_model == NODE_PRICE_DELTA: if ipp.node_price_model == NODE_PRICE_DELTA or ipp.node_price_model == NODE_PRICE_LAMBDA:
# imports # imports
imports_qpk = { imports_qpk = {
qpk: pyo.value( qpk: pyo.value(
...@@ -152,7 +152,7 @@ def statistics(ipp: InfrastructurePlanningProblem, ...@@ -152,7 +152,7 @@ def statistics(ipp: InfrastructurePlanningProblem,
} }
else: else:
# not in a block # not in a block
if ipp.node_price_model == NODE_PRICE_DELTA: if ipp.node_price_model == NODE_PRICE_DELTA or ipp.node_price_model == NODE_PRICE_LAMBDA:
# imports # imports
imports_qpk = { imports_qpk = {
qpk: pyo.value( qpk: pyo.value(
......
...@@ -221,6 +221,7 @@ class TestESIPPProblem: ...@@ -221,6 +221,7 @@ class TestESIPPProblem:
# no sos, regular time intervals # no sos, regular time intervals
ipp = build_solve_ipp( ipp = build_solve_ipp(
solver='scip' if node_price_model == NODE_PRICE_LAMBDA else 'glpk',
solver_options={}, solver_options={},
perform_analysis=False, perform_analysis=False,
plot_results=False, # True, plot_results=False, # True,
...@@ -351,6 +352,7 @@ class TestESIPPProblem: ...@@ -351,6 +352,7 @@ class TestESIPPProblem:
# no sos, regular time intervals # no sos, regular time intervals
ipp = build_solve_ipp( ipp = build_solve_ipp(
solver='scip' if node_price_model == NODE_PRICE_LAMBDA else 'glpk',
solver_options={}, solver_options={},
perform_analysis=False, perform_analysis=False,
plot_results=False, # True, plot_results=False, # True,
...@@ -680,6 +682,7 @@ class TestESIPPProblem: ...@@ -680,6 +682,7 @@ class TestESIPPProblem:
# no sos, regular time intervals # no sos, regular time intervals
ipp = build_solve_ipp( ipp = build_solve_ipp(
solver='scip' if node_price_model == NODE_PRICE_LAMBDA else 'glpk',
solver_options={}, solver_options={},
perform_analysis=False, perform_analysis=False,
plot_results=False, # True, plot_results=False, # True,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment