def get_power_flow_interface_expr_ptdf(model, interface_name, PTDF, rel_ptdf_tol=None, abs_ptdf_tol=None): """ Create a pyomo power flow expression from PTDF matrix for an interface """ if rel_ptdf_tol is None: rel_ptdf_tol = 0. if abs_ptdf_tol is None: abs_ptdf_tol = 0. const = PTDF.get_interface_const(interface_name) max_coef = PTDF.get_interface_ptdf_abs_max(interface_name) ptdf_tol = max(abs_ptdf_tol, rel_ptdf_tol * max_coef) m_p_nw = model.p_nw ## if model.p_nw is Var, we can use LinearExpression ## to build these dense constraints much faster if isinstance(m_p_nw, pe.Var): coef_list = list() var_list = list() for bus_name, coef in PTDF.get_interface_ptdf_iterator(interface_name): if abs(coef) >= ptdf_tol: coef_list.append(coef) var_list.append(m_p_nw[bus_name]) if interface_name in model.pfi_slack_neg: coef_list.append(1) var_list.append(model.pfi_slack_neg[interface_name]) if interface_name in model.pfi_slack_pos: coef_list.append(-1) var_list.append(model.pfi_slack_pos[interface_name]) lin_expr_list = [const] + coef_list + var_list expr = LinearExpression(lin_expr_list) else: expr = quicksum( (coef * m_p_nw[bus_name] for bus_name, coef in PTDF.get_interface_ptdf_iterator( interface_name) if abs(coef) >= ptdf_tol), start=const, linear=True) if interface_name in model.pfi_slack_neg: expr += model.pfi_slack_neg[interface_name] if interface_name in model.pfi_slack_pos: expr -= model.pfi_slack_pos[interface_name] return expr
def get_branch_loss_expr_ptdf_approx(model, branch_name, PTDF, rel_ptdf_tol=None, abs_ptdf_tol=None): """ Create a pyomo power flow loss expression from PTDF matrix """ if rel_ptdf_tol is None: rel_ptdf_tol = 0. if abs_ptdf_tol is None: abs_ptdf_tol = 0. const = PTDF.get_branch_losses_phase_shift(branch_name) const += PTDF.get_branch_ldf_c(branch_name) const += PTDF.get_branch_phi_losses_adj(branch_name) max_coef = PTDF.get_branch_ldf_abs_max(branch_name) ptdf_tol = max(abs_ptdf_tol, rel_ptdf_tol * max_coef) ## NOTE: It would be easy to hold on to the 'ptdf' dictionary here, ## if we wanted to m_p_nw = model.p_nw ## if model.p_nw is Var, we can use LinearExpression ## to build these dense constraints much faster if isinstance(m_p_nw, pe.Var): coef_list = list() var_list = list() for bus_name, coef in PTDF.get_branch_ldf_iterator(branch_name): if abs(coef) >= ptdf_tol: coef_list.append(coef) var_list.append(m_p_nw[bus_name]) lin_expr_list = [const] + coef_list + var_list expr = LinearExpression(lin_expr_list) else: expr = quicksum( (coef * m_p_nw[bus_name] for bus_name, coef in PTDF.get_branch_ldf_iterator(branch_name) if abs(coef) >= ptdf_tol), start=const, linear=True) return expr
def create_optimization_model(self, config): self.logger.info('Creating optimization model.') # Consider using context managers # limit_sell = False # GET COMPONENTS FROM SYSTEM if self.system.has_battery: battery = self.system.get_battery_object() if self.system.has_external_grid: supply = self.system.get_external_grid_object() # STARTING MODEL m = pk.block() # Track the default attributes of the model to be aware of which the user adds. default_attributes = set(m.__dict__.keys()) default_attributes.add('default_attributes') # SETS m.periods = range(config['periods']) m.E_set = [] # VARIABLES m.E = pk.variable_dict() if self.system.has_stochastic_generators and not self.system.has_external_grid: m.E_set.append('stochastic') m.E['stochastic'] = pk.variable_list() for t in m.periods: m.E['stochastic'].append( pk.variable(domain_type=pk.RealSet, lb=0, ub=self.system.stochastic_electrical_gen[t])) if self.system.has_external_grid: m.E_set.append('buy') m.E_set.append('sell') m.E['buy'] = pk.variable_list() for _ in m.periods: m.E['buy'].append(pk.variable(domain=pk.NonNegativeReals)) m.E['sell'] = pk.variable_list() for _ in m.periods: m.E['sell'].append(pk.variable(domain=pk.NonNegativeReals)) m.y_grid = pk.variable_list() for _ in m.periods: m.y_grid.append( pk.variable(domain_type=pk.IntegerSet, lb=0, ub=1)) if self.system.has_battery: m.E_set.append('batt_chrg') m.E_set.append('batt_dis') m.E['batt_chrg'] = pk.variable_list() for _ in m.periods: # The upper bound are impose in the constraints below m.E['batt_chrg'].append( pk.variable(domain_type=pk.RealSet, lb=0)) m.E['batt_dis'] = pk.variable_list() for _ in m.periods: m.E['batt_dis'].append( pk.variable(domain_type=pk.RealSet, lb=0)) m.y_bat = pk.variable_list() for _ in m.periods: m.y_bat.append( pk.variable(domain_type=pk.IntegerSet, lb=0, ub=1)) m.soc = pk.variable_list() for _ in m.periods: m.soc.append( pk.variable(domain_type=pk.RealSet, lb=battery.soc_lb, ub=battery.soc_ub)) # Extra soc variable for the last value of soc that should be >= soc_l m.soc.append( pk.variable(domain_type=pk.RealSet, lb=battery.soc_l, ub=battery.soc_ub)) # PARAMETERS if self.system.has_external_grid: m.prices = { 'buy': supply.electricity_purchase_prices.copy(), 'sell': supply.electricity_selling_prices.copy(), } # OBJECTIVE FUNCTION obj_exp = 0 obj_sense = pk.minimize if self.system.has_external_grid: obj_exp = quicksum((m.E['buy'][t] * m.prices['buy'][t] for t in m.periods), linear=True) \ - quicksum((m.E['sell'][t] * m.prices['sell'][t] for t in m.periods), linear=True) m.obj = pk.objective(obj_exp, sense=obj_sense) # CONSTRAINTS # Grid constraints # if limit_sell: # m.c_limit_sell = pk.constraint( # lb=0, body=system['selling_ratio'] # * sum(m.E['buy'][t] + system['E_pv'][t] for t in m.periods) # - sum(m.E['sell'][t] for t in m.periods)) grid_m = 1e5 m.cl_y_buy = pk.constraint_list() for t in m.periods: m.cl_y_buy.append( pk.constraint(body=m.y_grid[t] * grid_m - m.E['buy'][t], lb=0)) m.cl_y_sell = pk.constraint_list() for t in m.periods: m.cl_y_sell.append( pk.constraint(body=(1 - m.y_grid[t]) * grid_m - m.E['sell'][t], lb=0)) # Balance constraints energy_balance_exp = [0 for _ in m.periods] if self.system.has_fix_loads: for t in m.periods: energy_balance_exp[t] = -1 * self.system.fix_electrical_load[t] if self.system.has_external_grid: for t in m.periods: energy_balance_exp[ t] = energy_balance_exp[t] + m.E['buy'][t] - m.E['sell'][t] if self.system.has_battery: for t in m.periods: energy_balance_exp[t] = energy_balance_exp[t] + m.E[ 'batt_dis'][t] - m.E['batt_chrg'][t] if self.system.has_stochastic_generators and not self.system.has_external_grid: for t in m.periods: energy_balance_exp[ t] = energy_balance_exp[t] + m.E['stochastic'][t] else: for t in m.periods: energy_balance_exp[t] = energy_balance_exp[ t] + self.system.stochastic_electrical_gen[t] m.cl_balance = pk.constraint_list() for t in m.periods: m.cl_balance.append( pk.constraint(body=energy_balance_exp[t], rhs=0)) # Battery constraints and restrictions if self.system.has_battery: m.soc[0].fix(battery.soc_0) m.cl_soc = pk.constraint_list() for t in m.periods: m.cl_soc.append( pk.constraint( body=battery.batt_C * (m.soc[t + 1] - m.soc[t]) + 1 / battery.batt_dis_per * m.E['batt_dis'][t] - battery.batt_chrg_per * m.E['batt_chrg'][t], rhs=0)) m.cl_y_char = pk.constraint_list() for t in m.periods: m.cl_y_char.append( pk.constraint(body=m.y_bat[t] * battery.batt_chrg_speed - m.E['batt_chrg'][t], lb=0)) m.cl_y_dis = pk.constraint_list() for t in m.periods: m.cl_y_char.append( pk.constraint( body=(1 - m.y_bat[t]) * battery.batt_dis_speed - m.E['batt_dis'][t], lb=0)) # FINISHING # Determine the user defined attributes (written in this source code) by subtracting the defaults one. all_attributes = set(m.__dict__.keys()) m.user_defined_attributes = list(all_attributes - default_attributes) self.optimization_model = m return m