From a4b3fb3747706b5efc8def62f203f09509890eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20L=2E=20Magalh=C3=A3es?= <pmlpm@posteo.de> Date: Fri, 26 Jul 2024 01:01:23 +0200 Subject: [PATCH] Implemented the price functions using a block component. --- src/topupopt/problems/esipp/blocks/prices.py | 626 +++++-------------- src/topupopt/problems/esipp/model.py | 11 +- src/topupopt/problems/esipp/problem.py | 12 +- tests/test_esipp_prices.py | 2 +- 4 files changed, 177 insertions(+), 474 deletions(-) diff --git a/src/topupopt/problems/esipp/blocks/prices.py b/src/topupopt/problems/esipp/blocks/prices.py index 404c852..870a71e 100644 --- a/src/topupopt/problems/esipp/blocks/prices.py +++ b/src/topupopt/problems/esipp/blocks/prices.py @@ -1,10 +1,12 @@ # imports import pyomo.environ as pyo +import math + # ***************************************************************************** # ***************************************************************************** -def add_prices_block( +def add_price_functions( model: pyo.AbstractModel, **kwargs ): @@ -12,18 +14,18 @@ def add_prices_block( # ************************************************************************* # ************************************************************************* - # model.node_price_block = pyo.Block(model.set_QPK) - - price_other(model, **kwargs) - # price_block_other(model, **kwargs) + # price_other(model, **kwargs) + price_other_block(model, **kwargs) + + # ************************************************************************* + # ************************************************************************* # ***************************************************************************** # ***************************************************************************** -# TODO: try to implement it as a block (might make things look cleaner) -def price_block_other( +def price_other_block( model: pyo.AbstractModel, - convex_price_function: bool = True, + # convex_price_function: bool = True, enable_default_values: bool = True, enable_validation: bool = True, enable_initialisation: bool = True @@ -31,485 +33,177 @@ def price_block_other( # auxiliary set for pyomo model.set_GLQPK = model.set_GL_exp_imp*model.set_QPK + + # create a block for a transshipment node during a given time interval + def rule_block_prices(b, g, l, q, p, k): + + # ********************************************************************* + # ********************************************************************* + + # sets + + # set of price segments + 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) + + # ********************************************************************* + # ********************************************************************* + + # parameters - # set of price segments - model.set_S = pyo.Set(model.set_GLQPK) - - # set of GLQKS tuples - def init_set_GLQPKS(m): - return ( - (g, l, q, p, k, s) - # for (g,l) in m.set_GL_exp_imp - # for (q,k) in m.set_QK - for (g, l, q, p, k) in m.set_S - for s in m.set_S[(g, l, q, p, k)] - ) - - model.set_GLQPKS = pyo.Set( - dimen=6, initialize=(init_set_GLQPKS if enable_initialisation else None) - ) - - # ************************************************************************* - # ************************************************************************* - - # parameters - - # resource prices + # resource prices + b.param_p_s = pyo.Param(b.set_S, within=pyo.NonNegativeReals) + + # price function convexity + b.param_price_function_is_convex = pyo.Param(within=pyo.Boolean) - model.param_p_glqpks = pyo.Param(model.set_GLQPKS, within=pyo.NonNegativeReals) + # maximum resource volumes for each prices + b.param_v_max_s = pyo.Param(b.set_S, within=pyo.NonNegativeReals) - # price function convexity - - model.param_price_function_is_convex = pyo.Param( - model.set_GLQPK, - within=pyo.Boolean + # ********************************************************************* + # ********************************************************************* + + # variables + + # ********************************************************************* + # ********************************************************************* + + # TODO: consider replacing None in the bounds with inf in the parameter + + # import and export flows + def bounds_var_trans_flows_s(b, s): + if s in b.param_v_max_s: + # predefined finite capacity + return (0, b.param_v_max_s[s]) + else: + # infinite capacity + return (0, None) + b.var_trans_flows_s = pyo.Var( + b.set_S, + within=pyo.NonNegativeReals, + bounds=bounds_var_trans_flows_s ) - - # maximum resource volumes for each prices - - model.param_v_max_glqpks = pyo.Param( - model.set_GLQPKS, - within=pyo.NonNegativeReals + + # ********************************************************************* + # ********************************************************************* + + # import flow costs and export flow revenues + def rule_constr_trans_monetary_flows(b): + if (g,l) in b.parent_block().set_GL_imp: + return ( + sum(b.var_trans_flows_s[s]*b.param_p_s[s] + for s in b.set_S) + == b.parent_block().var_ifc_glqpk[(g,l,q,p,k)] + ) + else: + return ( + sum(b.var_trans_flows_s[s]*b.param_p_s[s] + for s in b.set_S) + == b.parent_block().var_efr_glqpk[(g,l,q,p,k)] + ) + b.constr_trans_monetary_flows = pyo.Constraint( + rule=rule_constr_trans_monetary_flows ) - \ - # price block - model.price_block = pyo.Block(model.set_GLQPK) - - # ************************************************************************* - # ************************************************************************* - - # variables - - # ************************************************************************* - # ************************************************************************* - - # import and export flows - def bounds_var_trans_flows_glqpks(m, g, l, q, p, k, s): - if (g, l, q, p, k, s) in m.param_v_max_glqpks: - # predefined finite capacity - return (0, m.param_v_max_glqpks[(g, l, q, p, k, s)]) - else: - # infinite capacity - return (0, None) - model.var_trans_flows_glqpks = pyo.Var( - model.set_GLQPKS, within=pyo.NonNegativeReals, bounds=bounds_var_trans_flows_glqpks - ) - - # ************************************************************************* - # ************************************************************************* - - # import flow costs and export flow revenues - def rule_constr_trans_monetary_flows(m, g, l, q, p, k): - if (g,l) in m.set_GL_imp: + + # imported and exported flows + def rule_constr_trans_flows(b): + if (g,l) in b.parent_block().set_GL_imp: + return sum( + b.parent_block().var_v_glljqk[(g,l,l_star,j,q,k)] + for l_star in b.parent_block().set_L[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 + ) == sum(b.var_trans_flows_s[s] for s in b.set_S) + else: + return sum( + b.parent_block().var_v_glljqk[(g,l_star,l,j,q,k)] + * b.parent_block().param_eta_glljqk[(g,l_star,l,j,q,k)] + for l_star in b.parent_block().set_L[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 + ) == sum(b.var_trans_flows_s[s] for s in b.set_S) + b.constr_trans_flows = pyo.Constraint(rule=rule_constr_trans_flows) + + # ********************************************************************* + # ********************************************************************* + + # non-convex price functions + + # delta variables + b.var_active_segment_s = pyo.Var(b.set_S, within=pyo.Binary) + + # segments must be empty if the respective delta variable is zero + 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 ( - sum( - m.var_trans_flows_glqpks[(g, l, q, p, k, s)] - * m.param_p_glqpks[(g, l, q, p, k, s)] - for s in m.set_S[(g, l, q, p, k)] + b.var_trans_flows_s[s] <= + b.param_v_max_s[s]*b.var_active_segment_s[s] ) - == m.var_ifc_glqpk[(g, l, q, p, k)] + b.constr_empty_segment_if_delta_zero = pyo.Constraint( + b.set_S, rule=rule_constr_empty_segment_if_delta_zero ) - else: + + # 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 ( - sum( - m.var_trans_flows_glqpks[(g, l, q, p, k, s)] - * m.param_p_glqpks[(g, l, q, p, k, s)] - for s in m.set_S[(g, l, q, p, k)] + b.var_active_segment_s[s] >= + b.var_active_segment_s[s+1] ) - == m.var_efr_glqpk[(g, l, q, p, k)] + b.constr_delta_summing_logic = pyo.Constraint( + b.set_S, rule=rule_constr_delta_summing_logic ) - model.constr_trans_monetary_flows = pyo.Constraint( - model.set_GLQPK, rule=rule_constr_trans_monetary_flows - ) - - # imported and exported flows - def rule_constr_trans_flows(m, g, l, q, p, k): - if (g,l) in m.set_GL_imp: - return sum( - m.var_v_glljqk[(g, l, l_star, j, q, k)] - for l_star in m.set_L[g] - if l_star not in m.set_L_imp[g] - for j in m.set_J[(g, l, l_star)] # only directed arcs - ) == sum(m.var_trans_flows_glqpks[(g, l, q, p, k, s)] for s in m.set_S[(g, l, q, p, k)]) - else: - return sum( - m.var_v_glljqk[(g, l_star, l, j, q, k)] - * m.param_eta_glljqk[(g, l_star, l, j, q, k)] - for l_star in m.set_L[g] - if l_star not in m.set_L_exp[g] - for j in m.set_J[(g, l_star, l)] # only directed arcs - ) == sum(m.var_trans_flows_glqpks[(g, l, q, p, k, s)] for s in m.set_S[(g, l, q, p, k)]) - - model.constr_trans_flows = pyo.Constraint( - model.set_GLQPK, rule=rule_constr_trans_flows - ) - - # ************************************************************************* - # ************************************************************************* - - # non-convex price functions - # delta variables - model.var_active_segment_glqpks = pyo.Var( - model.set_GLQPKS, within=pyo.Binary - ) - - # segments must be empty if the respective delta variable is zero - def rule_constr_empty_segment_if_delta_zero(m, g, l, q, p, k, s): - if len(m.set_S[(g,l,q,p,k)]) == 1 or m.param_price_function_is_convex[(g,l,q,p,k)]: - # single segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - m.var_trans_flows_glqpks[(g,l,q,p,k,s)] <= - m.param_v_max_glqpks[(g,l,q,p,k,s)]* - m.var_active_segment_glqpks[(g,l,q,p,k,s)] - ) - model.constr_empty_segment_if_delta_zero = pyo.Constraint( - model.set_GLQPKS, 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(m, g, l, q, p, k, s): - if s == len(m.set_S[(g,l,q,p,k)])-1 or m.param_price_function_is_convex[(g,l,q,p,k)]: - # last segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - m.var_active_segment_glqpks[(g,l,q,p,k,s)] >= - m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] - ) - model.constr_delta_summing_logic = pyo.Constraint( - model.set_GLQPKS, 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(m, g, l, q, p, k, s): - if s == len(m.set_S[(g,l,q,p,k)])-1 or m.param_price_function_is_convex[(g,l,q,p,k)]: - # last segment, skip - # convex, skip - return pyo.Constraint.Skip - return ( - m.var_trans_flows_glqpks[(g,l,q,p,k,s)] >= - m.var_active_segment_glqpks[(g,l,q,p,k,s+1)]* - m.param_v_max_glqpks[(g,l,q,p,k,s)] + # 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 ) - # return ( - # m.var_if_glqpks[(g,l,q,p,k,s)]/m.param_v_max_glqpks[(g,l,q,p,k,s)] >= - # m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] - # ) - # return ( - # m.param_v_max_glqpks[(g,l,q,p,k,s)]-m.var_if_glqpks[(g,l,q,p,k,s)] <= - # m.param_v_max_glqpks[(g,l,q,p,k,s)]*(1- m.var_active_segment_glqpks[(g,l,q,p,k,s+1)]) - # ) - model.constr_fill_up_segment_before_next = pyo.Constraint( - model.set_GLQPKS, rule=rule_constr_fill_up_segment_before_next - ) - # ************************************************************************* - # ************************************************************************* - - # # non-convex price functions - - # if not convex_price_function: - # # delta variables - # model.var_active_segment_glqpks = pyo.Var( - # model.set_GLQPKS, within=pyo.Binary - # ) + # ********************************************************************* + # ********************************************************************* - # # segments must be empty if the respective delta variable is zero - # def rule_constr_empty_segment_if_delta_zero_imp(m, g, l, q, p, k, s): - # return ( - # m.var_if_glqpks[(g,l,q,p,k,s)] <= - # m.param_v_max_glqpks[(g,l,q,p,k,s)]* - # m.var_active_segment_glqpks[(g,l,q,p,k,s)] - # ) - # model.constr_empty_segment_if_delta_zero_imp = pyo.Constraint( - # model.set_GLQPKS_imp, rule=rule_constr_empty_segment_if_delta_zero_imp - # ) - - # # segments must be empty if the respective delta variable is zero - # def rule_constr_empty_segment_if_delta_zero_exp(m, g, l, q, p, k, s): - # return ( - # m.var_ef_glqpks[(g,l,q,p,k,s)] <= - # m.param_v_max_glqpks[(g,l,q,p,k,s)]* - # m.var_active_segment_glqpks[(g,l,q,p,k,s)] - # ) - # model.constr_empty_segment_if_delta_zero_exp = pyo.Constraint( - # model.set_GLQPKS_exp, rule=rule_constr_empty_segment_if_delta_zero_exp - # ) - - # # if delta var is one, previous ones must be one too - # def rule_constr_delta_summing_logic(m, g, l, q, p, k, s): - # if s == len(m.set_S)-1: - # return pyo.Constraint.Skip - # return ( - # m.var_active_segment_glqpks[(g,l,q,p,k,s)] >= - # m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] - # ) - # model.constr_delta_summing_logic = pyo.Constraint( - # model.set_GLQPKS, rule=rule_constr_delta_summing_logic - # ) - # # if delta var is zero, subsequent ones must also be zero - # def rule_constr_delta_next_zeros(m, g, l, q, p, k, s): - # if s == len(m.set_S)-1: - # return pyo.Constraint.Skip - # return ( - # 1-m.var_active_segment_glqpks[(g,l,q,p,k,s)] >= - # m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] - # ) - # model.constr_delta_next_zeros = pyo.Constraint( - # model.set_GLQPKS, rule=rule_constr_delta_next_zeros - # ) + model.block_prices = pyo.Block(model.set_GLQPK, rule=rule_block_prices) # ************************************************************************* # ************************************************************************* - - + +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** +# ***************************************************************************** # ***************************************************************************** # ***************************************************************************** - -# def price_other2( -# model: pyo.AbstractModel, -# convex_price_function: bool = False, -# enable_default_values: bool = True, -# enable_validation: bool = True, -# enable_initialisation: bool = True -# ): - -# # set of price segments -# model.set_S = pyo.Set(model.set_GL_exp_imp, model.set_QPK) - -# # set of GLQKS tuples -# def init_set_GLQPKS(m): -# return ( -# (g, l, q, p, k, s) -# # for (g,l) in m.set_GL_exp_imp -# # for (q,k) in m.set_QK -# for (g, l, q, p, k) in m.set_S -# for s in m.set_S[(g, l, q, p, k)] -# ) - -# model.set_GLQPKS = pyo.Set( -# dimen=6, initialize=(init_set_GLQPKS if enable_initialisation else None) -# ) - -# def init_set_GLQPKS_exp(m): -# return ( -# glqpks for glqpks in m.set_GLQPKS if glqpks[1] in m.set_L_exp[glqpks[0]] -# ) - -# model.set_GLQPKS_exp = pyo.Set( -# dimen=6, initialize=(init_set_GLQPKS_exp if enable_initialisation else None) -# ) - -# def init_set_GLQPKS_imp(m): -# return ( -# glqpks for glqpks in m.set_GLQPKS if glqpks[1] in m.set_L_imp[glqpks[0]] -# ) - -# model.set_GLQPKS_imp = pyo.Set( -# dimen=6, initialize=(init_set_GLQPKS_imp if enable_initialisation else None) -# ) - -# # ************************************************************************* -# # ************************************************************************* - -# # parameters - -# # resource prices - -# model.param_p_glqpks = pyo.Param(model.set_GLQPKS, within=pyo.NonNegativeReals) - -# # maximum resource volumes for each prices - -# model.param_v_max_glqpks = pyo.Param( -# model.set_GLQPKS, -# within=pyo.NonNegativeReals -# ) - -# # ************************************************************************* -# # ************************************************************************* - -# # variables - -# # ************************************************************************* -# # ************************************************************************* - -# # exported flow - -# # TODO: validate the bounds by ensuring inf. cap. only exists in last segm. - -# def bounds_var_ef_glqpks(m, g, l, q, p, k, s): -# if (g, l, q, p, k, s) in m.param_v_max_glqpks: -# # predefined finite capacity -# return (0, m.param_v_max_glqpks[(g, l, q, p, k, s)]) -# else: -# # infinite capacity -# return (0, None) - -# model.var_ef_glqpks = pyo.Var( -# model.set_GLQPKS_exp, within=pyo.NonNegativeReals, bounds=bounds_var_ef_glqpks -# ) - -# # imported flow - -# def bounds_var_if_glqpks(m, g, l, q, p, k, s): -# if (g, l, q, p, k, s) in m.param_v_max_glqpks: -# # predefined finite capacity -# return (0, m.param_v_max_glqpks[(g, l, q, p, k, s)]) -# else: -# # infinite capacity -# return (0, None) - -# model.var_if_glqpks = pyo.Var( -# model.set_GLQPKS_imp, within=pyo.NonNegativeReals, bounds=bounds_var_if_glqpks -# ) - -# # ************************************************************************* -# # ************************************************************************* - -# # exported flow revenue -# def rule_constr_exp_flow_revenue(m, g, l, q, p, k): -# return ( -# sum( -# m.var_ef_glqpks[(g, l, q, p, k, s)] -# * m.param_p_glqpks[(g, l, q, p, k, s)] -# for s in m.set_S[(g, l, q, p, k)] -# ) -# == m.var_efr_glqpk[(g, l, q, p, k)] -# ) - -# model.constr_exp_flow_revenue = pyo.Constraint( -# model.set_GL_exp, model.set_QPK, rule=rule_constr_exp_flow_revenue -# ) - -# # imported flow cost -# def rule_constr_imp_flow_cost(m, g, l, q, p, k): -# return ( -# sum( -# m.var_if_glqpks[(g, l, q, p, k, s)] -# * m.param_p_glqpks[(g, l, q, p, k, s)] -# for s in m.set_S[(g, l, q, p, k)] -# ) -# == m.var_ifc_glqpk[(g, l, q, p, k)] -# ) - -# model.constr_imp_flow_cost = pyo.Constraint( -# model.set_GL_imp, model.set_QPK, rule=rule_constr_imp_flow_cost -# ) - -# # exported flows -# def rule_constr_exp_flows(m, g, l, q, p, k): -# return sum( -# m.var_v_glljqk[(g, l_star, l, j, q, k)] -# * m.param_eta_glljqk[(g, l_star, l, j, q, k)] -# for l_star in m.set_L[g] -# if l_star not in m.set_L_exp[g] -# for j in m.set_J[(g, l_star, l)] # only directed arcs -# ) == sum(m.var_ef_glqpks[(g, l, q, p, k, s)] for s in m.set_S[(g, l, q, p, k)]) - -# model.constr_exp_flows = pyo.Constraint( -# model.set_GL_exp, model.set_QPK, rule=rule_constr_exp_flows -# ) - -# # imported flows -# def rule_constr_imp_flows(m, g, l, q, p, k): -# return sum( -# m.var_v_glljqk[(g, l, l_star, j, q, k)] -# for l_star in m.set_L[g] -# if l_star not in m.set_L_imp[g] -# for j in m.set_J[(g, l, l_star)] # only directed arcs -# ) == sum(m.var_if_glqpks[(g, l, q, p, k, s)] for s in m.set_S[(g, l, q, p, k)]) - -# model.constr_imp_flows = pyo.Constraint( -# model.set_GL_imp, model.set_QPK, rule=rule_constr_imp_flows -# ) - -# # ************************************************************************* -# # ************************************************************************* - -# # non-convex price functions - -# if not convex_price_function: - -# # delta variables -# model.var_active_segment_glqpks = pyo.Var( -# model.set_GLQPKS, within=pyo.Binary -# ) - -# # segments must be empty if the respective delta variable is zero -# def rule_constr_empty_segment_if_delta_zero_imp(m, g, l, q, p, k, s): -# return ( -# m.var_if_glqpks[(g,l,q,p,k,s)] <= -# m.param_v_max_glqpks[(g,l,q,p,k,s)]* -# m.var_active_segment_glqpks[(g,l,q,p,k,s)] -# ) -# model.constr_empty_segment_if_delta_zero_imp = pyo.Constraint( -# model.set_GLQPKS_imp, rule=rule_constr_empty_segment_if_delta_zero_imp -# ) - -# # segments must be empty if the respective delta variable is zero -# def rule_constr_empty_segment_if_delta_zero_exp(m, g, l, q, p, k, s): -# return ( -# m.var_ef_glqpks[(g,l,q,p,k,s)] <= -# m.param_v_max_glqpks[(g,l,q,p,k,s)]* -# m.var_active_segment_glqpks[(g,l,q,p,k,s)] -# ) -# model.constr_empty_segment_if_delta_zero_exp = pyo.Constraint( -# model.set_GLQPKS_exp, rule=rule_constr_empty_segment_if_delta_zero_exp -# ) - -# # 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(m, g, l, q, p, k, s): -# if s == len(m.set_S[(g,l,q,p,k)])-1: -# # last segment, skip -# return pyo.Constraint.Skip -# return ( -# m.var_active_segment_glqpks[(g,l,q,p,k,s)] >= -# m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] -# ) -# model.constr_delta_summing_logic = pyo.Constraint( -# model.set_GLQPKS, 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(m, g, l, q, p, k, s): -# if s == len(m.set_S[(g,l,q,p,k)])-1: -# # last segment, skip -# return pyo.Constraint.Skip -# if (g,l) in m.set_GL_imp: -# return ( -# m.var_if_glqpks[(g,l,q,p,k,s)] >= -# m.var_active_segment_glqpks[(g,l,q,p,k,s+1)]* -# m.param_v_max_glqpks[(g,l,q,p,k,s)] -# ) -# else: -# return ( -# m.var_ef_glqpks[(g,l,q,p,k,s)] >= -# m.var_active_segment_glqpks[(g,l,q,p,k,s+1)]* -# m.param_v_max_glqpks[(g,l,q,p,k,s)] -# ) -# # return ( -# # m.var_if_glqpks[(g,l,q,p,k,s)]/m.param_v_max_glqpks[(g,l,q,p,k,s)] >= -# # m.var_active_segment_glqpks[(g,l,q,p,k,s+1)] -# # ) -# # return ( -# # m.param_v_max_glqpks[(g,l,q,p,k,s)]-m.var_if_glqpks[(g,l,q,p,k,s)] <= -# # m.param_v_max_glqpks[(g,l,q,p,k,s)]*(1- m.var_active_segment_glqpks[(g,l,q,p,k,s+1)]) -# # ) -# model.constr_fill_up_segment_before_next = pyo.Constraint( -# model.set_GLQPKS, rule=rule_constr_fill_up_segment_before_next -# ) - # ***************************************************************************** # ***************************************************************************** def price_other( model: pyo.AbstractModel, - convex_price_function: bool = True, + # convex_price_function: bool = True, enable_default_values: bool = True, enable_validation: bool = True, enable_initialisation: bool = True @@ -555,7 +249,8 @@ def price_other( model.param_v_max_glqpks = pyo.Param( model.set_GLQPKS, - within=pyo.NonNegativeReals + within=pyo.NonNegativeReals, + # default=math.inf ) # ************************************************************************* @@ -568,6 +263,7 @@ def price_other( # import and export flows def bounds_var_trans_flows_glqpks(m, g, l, q, p, k, s): + # return (0, m.param_v_max_glqpks[(g, l, q, p, k, s)]) if (g, l, q, p, k, s) in m.param_v_max_glqpks: # predefined finite capacity return (0, m.param_v_max_glqpks[(g, l, q, p, k, s)]) @@ -693,6 +389,8 @@ def price_other( # ***************************************************************************** # ***************************************************************************** +# TODO: implement the lambda model + def price_block_lambda(model: pyo.AbstractModel, **kwargs): raise NotImplementedError @@ -700,6 +398,8 @@ def price_block_lambda(model: pyo.AbstractModel, **kwargs): # ***************************************************************************** # ***************************************************************************** +# TODO: implement the delta model + def price_block_delta(model: pyo.AbstractModel, **kwargs): raise NotImplementedError diff --git a/src/topupopt/problems/esipp/model.py b/src/topupopt/problems/esipp/model.py index 62e387c..ade66bb 100644 --- a/src/topupopt/problems/esipp/model.py +++ b/src/topupopt/problems/esipp/model.py @@ -3,7 +3,7 @@ import pyomo.environ as pyo from .blocks.networks import add_network_restrictions -from .blocks.prices import add_prices_block +from .blocks.prices import add_price_functions # ***************************************************************************** # ***************************************************************************** @@ -57,33 +57,26 @@ def create_model( # ************************************************************************* # set of assessments - model.set_Q = pyo.Set() # TODO: use rangesets for time-related sets # set of time step intervals for each assessment - model.set_K_q = pyo.Set(model.set_Q) # set of representative evaluation periods for each assessment - model.set_P_q = pyo.Set(model.set_Q) # set of networks - model.set_G = pyo.Set() # set of nodes on each network - model.set_L = pyo.Set(model.set_G) # set of importing nodes on each network - model.set_L_imp = pyo.Set(model.set_G, within=model.set_L) # set of exporting nodes on each network - model.set_L_exp = pyo.Set(model.set_G, within=model.set_L) # ************************************************************************* @@ -2163,7 +2156,7 @@ def create_model( ) # prices - add_prices_block(model) + add_price_functions(model) # ************************************************************************* # ************************************************************************* diff --git a/src/topupopt/problems/esipp/problem.py b/src/topupopt/problems/esipp/problem.py index 8b0dd6b..c05b664 100644 --- a/src/topupopt/problems/esipp/problem.py +++ b/src/topupopt/problems/esipp/problem.py @@ -2548,7 +2548,7 @@ class InfrastructurePlanningProblem(EnergySystem): } # maximum resource volume per segment (infinity is the default) - + param_v_max_glqpks = { (g, l, q, p, k, s): self.networks[g] .nodes[l][Network.KEY_NODE_PRICES][(q, p, k)] @@ -3511,6 +3511,16 @@ class InfrastructurePlanningProblem(EnergySystem): "param_arc_sns_sos1_weights_glljqk": param_arc_sns_sos1_weights_glljqk, # ***************************************************************** # ***************************************************************** + "block_prices": { + (*gl,*qpk): { + 'param_price_function_is_convex': {None: param_price_function_is_convex[(*gl,*qpk)]}, + 'set_S': {None: set_S[(*gl,*qpk)]}, + 'param_p_s': {s: param_p_glqpks[(*gl,*qpk,s)] for s in set_S[(*gl,*qpk)]}, + 'param_v_max_s': {s: param_v_max_glqpks[(*gl,*qpk,s)] for s in set_S[(*gl,*qpk)] if (*gl,*qpk,s) in param_v_max_glqpks}, + } + for gl in set_GL_exp_imp + for qpk in set_QPK + } } } diff --git a/tests/test_esipp_prices.py b/tests/test_esipp_prices.py index 0bccfd4..9f3bf25 100644 --- a/tests/test_esipp_prices.py +++ b/tests/test_esipp_prices.py @@ -681,7 +681,7 @@ class TestESIPPProblem: max_number_parallel_arcs={}, simplify_problem=False, ) - + ipp.instance.pprint() assert not ipp.has_peak_total_assessments() assert ipp.results["Problem"][0]["Number of constraints"] == 14 # 10 before nonconvex block assert ipp.results["Problem"][0]["Number of variables"] == 13 # 11 before nonconvex block -- GitLab