def declare_pg_delta_pg_con(model, index_set, p_costs): m = model m.pg_delta_pg_con_set = pe.Set() m.pg_delta_pg_con = pe.Constraint(m.pg_delta_pg_con_set) for gen_name in pw_gen_generator(index_set, p_costs): p_min = m.pg[gen_name].lb p_max = m.pg[gen_name].ub curve = p_costs[gen_name] cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=p_min, p_max=p_max, gen_name=gen_name) m.pg_delta_pg_con_set.add(gen_name) lin_coefs = [-1] lin_vars = [m.pg[gen_name]] for ndx, ((o1, c1), (o2, c2)) in enumerate(zip(cleaned_values, cleaned_values[1:])): lin_coefs.append(1) lin_vars.append(m.delta_pg[gen_name, ndx]) expr = LinearExpression(constant=cleaned_values[0][0], linear_coefs=lin_coefs, linear_vars=lin_vars) m.pg_delta_pg_con[gen_name] = (expr, 0)
def declare_expression_qg_operating_cost(model, index_set, q_costs, pw_formulation='delta'): """ Create the Expression objects to represent the operating costs for the reactive power of each of the generators. """ m = model expr_set = decl.declare_set('_expr_qg_operating_cost', model=model, index_set=index_set) m.qg_operating_cost = pe.Expression(expr_set) for gen_name in expr_set: if gen_name in q_costs: if q_costs[gen_name]['cost_curve_type'] == 'polynomial': m.qg_operating_cost[gen_name] = sum(v*m.qg[gen_name]**i for i, v in q_costs[gen_name]['values'].items()) elif q_costs[gen_name]['cost_curve_type'] == 'piecewise': if pw_formulation == 'delta': q_min = m.qg[gen_name].lb q_max = m.qg[gen_name].ub curve = q_costs[gen_name] cleaned_values = tx_utils.validate_and_clean_cost_curve(curve=curve, curve_type='cost_curve', p_min=q_min, p_max=q_max, gen_name=gen_name) expr = cleaned_values[0][1] for ndx, ((o1, c1), (o2, c2)) in enumerate(zip(cleaned_values, cleaned_values[1:])): slope = (c2 - c1) / (o2 - o1) expr += slope * m.delta_pg[gen_name, ndx] m.qg_operating_cost[gen_name] = expr else: m.qg_operating_cost[gen_name] = m.qg_cost[gen_name] else: raise ValueError(f"Unrecognized cost_cureve_type: {q_costs[gen_name]['cost_curve_type']}") else: m.qg_operating_cost[gen_name] = 0
def test_pw_nonconvex(self): curve = example_pw_curve() curve['values'].insert(2, (35, _example_quadratic(20))) with self.assertRaises(ValueError): cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None)
def test_wrong_curve_type(self): curve = example_pw_curve() curve['data_type'] = 'blah' with self.assertRaises(ValueError): cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None)
def test_pw_simple(self): curve = example_pw_curve() cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None) self.assertEqual(cleaned_values, curve['values']) self.assertIsNot(cleaned_values, curve['values'])
def test_poly_cubic(self): curve = example_poly_curve() curve['values'][3] = 1 with self.assertRaises(ValueError): cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=15, p_max=85, gen_name='foo', t=None)
def test_extra_pw_pieces_above_pmax(self): curve = example_pw_curve() cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=70, gen_name='foo', t=None) self.assertEqual(cleaned_values, curve['values'][:-1]) self.assertIsNot(cleaned_values, curve['values'])
def test_pw_repeat_value_and_cost(self): curve = example_pw_curve() orig_values = copy.deepcopy(curve['values']) curve['values'].insert(2, (30, _example_quadratic(30))) cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None) self.assertEqual(cleaned_values, orig_values)
def test_pw_high_p_max(self): curve = example_pw_curve() expected_values = copy.deepcopy(curve['values']) expected_values.pop(-1) expected_values.append((95, 543)) cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=95, gen_name='foo', t=None) self.assertEqual(cleaned_values, expected_values) self.assertIsNot(cleaned_values, curve['values'])
def test_pw_low_p_min(self): curve = example_pw_curve() expected_values = copy.deepcopy(curve['values']) expected_values.pop(0) expected_values.insert(0, (5, 3)) cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=5, p_max=90, gen_name='foo', t=None) self.assertEqual(cleaned_values, expected_values) self.assertIsNot(cleaned_values, curve['values'])
def test_pw_repeated_slope(self): curve = dict() curve['data_type'] = 'cost_curve' curve['cost_curve_type'] = 'piecewise' curve['values'] = [(10, 20), (30, 40), (50, 60), (70, 80), (90, 100)] cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None) expected_values = [(10, 20), (90, 100)] self.assertEqual(cleaned_values, expected_values) self.assertIsNot(expected_values, curve['values'])
def test_pw_no_values(self): curve = example_pw_curve() curve['values'] = list() with self.assertLogs('egret.model_library.transmission.tx_utils', level=logging.WARNING) as cm: cleaned_values = tx_utils.validate_and_clean_cost_curve( curve=curve, curve_type='cost_curve', p_min=10, p_max=90, gen_name='foo', t=None) self.assertEqual(cleaned_values, curve['values']) self.assertIsNot(cleaned_values, curve['values']) self.assertEqual(cm.output, [ 'WARNING:egret.model_library.transmission.tx_utils:WARNING: Generator foo has no cost information associated with it' ])
def declare_var_delta_qg(model, index_set, q_costs): m = model m.delta_qg_set = pe.Set(dimen=2) m.delta_qg = pe.Var(m.delta_qg_set) for gen_name in pw_gen_generator(index_set, q_costs): q_min = m.qg[gen_name].lb q_max = m.qg[gen_name].ub curve = q_costs[gen_name] cleaned_values = tx_utils.validate_and_clean_cost_curve(curve=curve, curve_type='cost_curve', p_min=q_min, p_max=q_max, gen_name=gen_name) for ndx, ((o1, c1), (o2, c2)) in enumerate(zip(cleaned_values, cleaned_values[1:])): m.delta_qg_set.add((gen_name, ndx)) m.delta_qg[gen_name, ndx].setlb(0) m.delta_qg[gen_name, ndx].setub(o2 - o1)
def _pw_cost_helper(cost_dict, cost_var, gen_var, pw_cost_set, gen_name, indexed_pw_cost_con): if cost_dict['cost_curve_type'] == 'polynomial': pass elif cost_dict['cost_curve_type'] == 'piecewise': cleaned_values = tx_utils.validate_and_clean_cost_curve(cost_dict, curve_type='cost_curve', p_min=gen_var.lb, p_max=gen_var.ub, gen_name=gen_name) if len(cleaned_values) > 1: for ndx, ((pt1, cost1), (pt2, cost2)) in enumerate(zip(cleaned_values, cleaned_values[1:])): slope = (cost2 - cost1) / (pt2 - pt1) intercept = cost2 - slope * pt2 pw_cost_set.add((gen_name, ndx)) indexed_pw_cost_con[gen_name, ndx] = cost_var >= slope * gen_var + intercept else: intercept = cleaned_values[0][1] pw_cost_set.add((gen_name, 0)) indexed_pw_cost_con[gen_name, 0] = cost_var == intercept else: raise ValueError(f"Unrecognized cost_curve_type: {cost_dict['cost_curve_type']}")