Skip to content

Commit 0eb24fb

Browse files
committed
Update variable_func.py
1 parent def0b1e commit 0eb24fb

File tree

2 files changed

+73
-104
lines changed

2 files changed

+73
-104
lines changed

src/pownet/optim_model/variable_func.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
from pownet.data_utils import (
88
get_capacity_value,
9-
get_unit_hour_from_varname,
10-
get_edge_hour_from_varname,
119
)
1210

1311

@@ -63,8 +61,7 @@ def update_var_with_variable_ub(
6361
Returns:
6462
None
6563
"""
66-
for v in variables.values():
67-
unit, t = get_unit_hour_from_varname(v.VarName)
64+
for (unit, t), v in variables.items():
6865
capacity_value = get_capacity_value(t, unit, step_k, capacity_df)
6966
v.ub = capacity_value
7067
return
@@ -78,7 +75,7 @@ def update_flow_vars(
7875
) -> None:
7976
"""Update the lower and upper bounds of the flow variables based on the capacity dataframes"""
8077
hours_per_step = 24
81-
for flow_variable in flow_variables.values():
82-
edge, t = get_edge_hour_from_varname(flow_variable.VarName)
78+
for (node1, node2, t), flow_variable in flow_variables.items():
79+
edge = (node1, node2)
8380
line_capacity = capacity_df.loc[t + (step_k - 1) * hours_per_step, edge]
8481
flow_variable.ub = line_capacity * line_capacity_factor
Lines changed: 70 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
1-
"""test_variable_func.py"""
1+
"""test_variable_func.py: Unit tests for variable_func.py."""
22

33
import unittest
44
from unittest.mock import MagicMock, patch, call
55
import pandas as pd
66

7+
# Assuming variable_func is in pownet.optim_model directory
8+
# Adjust the import path if your directory structure is different.
9+
# For example, if pownet is in your PYTHONPATH:
710
from pownet.optim_model import variable_func
811

12+
# If variable_func.py is in the same directory as the test for local testing,
13+
# you might use:
14+
# import variable_func
15+
916

1017
class TestVariableFunctions(unittest.TestCase):
1118

12-
@classmethod
13-
def setUpClass(cls):
14-
"""Set up class-level resources or patches before any tests in the class run."""
15-
variable_func.VAR_PREFIX_THERMAL_GENERATION = "thermal_generation"
19+
# Removed setUpClass as VAR_PREFIX_THERMAL_GENERATION is no longer used
20+
# in variable_func.py
1621

1722
def setUp(self):
1823
"""Set up common test data and mocks."""
1924

20-
self.VAR_PREFIX_THERMAL_GENERATION = "thermal_generation"
21-
22-
self.timesteps = range(
23-
3
24-
) # Global timestep as per user request (implicitly via usage)
25+
self.timesteps = range(3)
2526
self.units = ["gen_A", "gen_B"]
2627
self.edges = [("node1", "node2"), ("node2", "node3")]
27-
self.step_k = 1 # Default step_k, can be overridden in specific tests
28+
self.step_k = 1 # Default step_k, can be overridden
2829

2930
# Mock Gurobi model
3031
self.mock_model = MagicMock()
@@ -37,9 +38,6 @@ def setUp(self):
3738
self.dummy_capacity_df = pd.DataFrame({"dummy_col": [1, 2, 3]})
3839

3940
# More structured capacity DataFrame for update_flow_vars
40-
# Index needs to cover t + (step_k - 1) * 24
41-
# For step_k=1, t=0,1,2 -> index 0,1,2
42-
# For step_k=2, t=0,1,2 -> index 24,25,26
4341
idx = pd.RangeIndex(start=0, stop=50, step=1) # Sufficient for a few steps
4442
data_for_flow_df = {
4543
self.edges[0]: [100 + i for i in range(50)],
@@ -54,12 +52,12 @@ def test_add_var_with_variable_ub(self, mock_get_capacity_value, mock_grb_module
5452
var_name = "test_var"
5553
step_k_test = 2
5654

55+
# Mock the GRB constant
5756
mock_grb_module.CONTINUOUS = "MOCK_GRB_CONTINUOUS_TYPE"
5857

59-
# Define a side effect for mock_get_capacity_value to simulate different capacities
58+
# Define a side effect for mock_get_capacity_value
6059
def capacity_side_effect(t, unit, sk, df):
61-
# sk is step_k, df is capacity_df
62-
# Simple unique value based on inputs for verification
60+
self.assertIs(df, self.dummy_capacity_df) # Ensure correct df is passed
6361
if unit == self.units[0]:
6462
return 100 + t + sk
6563
elif unit == self.units[1]:
@@ -68,7 +66,7 @@ def capacity_side_effect(t, unit, sk, df):
6866

6967
mock_get_capacity_value.side_effect = capacity_side_effect
7068

71-
# Expected upper bounds dictionary
69+
# Expected upper bounds dictionary based on the side effect
7270
expected_ub_dict = {}
7371
for t_val in self.timesteps:
7472
for unit_val in self.units:
@@ -92,7 +90,7 @@ def capacity_side_effect(t, unit, sk, df):
9290
self.timesteps,
9391
lb=0,
9492
ub=expected_ub_dict,
95-
vtype="MOCK_GRB_CONTINUOUS_TYPE", # Check if the mocked GRB type is used
93+
vtype="MOCK_GRB_CONTINUOUS_TYPE",
9694
name=var_name,
9795
)
9896

@@ -114,151 +112,125 @@ def capacity_side_effect(t, unit, sk, df):
114112
)
115113

116114
@patch("pownet.optim_model.variable_func.get_capacity_value")
117-
@patch("pownet.optim_model.variable_func.get_unit_hour_from_varname")
118-
def test_update_var_with_variable_ub(
119-
self, mock_get_unit_hour_from_varname, mock_get_capacity_value
120-
):
115+
def test_update_var_with_variable_ub(self, mock_get_capacity_value):
121116
"""Test the update_var_with_variable_ub function."""
122117
step_k_test = 1
123118

124-
# Create mock Gurobi variables
119+
# Create mock Gurobi variables (VarName is not used by the new function logic)
125120
mock_gvar1 = MagicMock()
126-
mock_gvar1.VarName = (
127-
f"{variable_func.VAR_PREFIX_THERMAL_GENERATION}_{self.units[0]}[0]"
128-
)
129121
mock_gvar1.ub = 0 # Initial ub
130122

131123
mock_gvar2 = MagicMock()
132-
mock_gvar2.VarName = (
133-
f"{variable_func.VAR_PREFIX_THERMAL_GENERATION}_{self.units[1]}[1]"
134-
)
135124
mock_gvar2.ub = 0 # Initial ub
136125

137-
# Simulate a gp.tupledict by using a dictionary of these mocks
138-
# The function iterates over .values()
126+
mock_gvar3 = MagicMock() # For a different timestep
127+
mock_gvar3.ub = 0
128+
129+
# Simulate a gp.tupledict by using a Python dictionary of these mocks
130+
# Keys are (unit, t) as expected by the function's iteration
139131
mock_variables_dict = {
140-
(self.units[0], 0): mock_gvar1,
132+
(self.units[0], 0): mock_gvar1, # (unit, t)
141133
(self.units[1], 1): mock_gvar2,
134+
(self.units[0], 2): mock_gvar3,
142135
}
143136

144-
# Configure side effect for get_unit_hour_from_varname
145-
def unit_hour_side_effect(var_name):
146-
if var_name == mock_gvar1.VarName:
147-
return self.units[0], 0
148-
elif var_name == mock_gvar2.VarName:
149-
return self.units[1], 1
150-
return None, None # Should not happen with controlled inputs
151-
152-
mock_get_unit_hour_from_varname.side_effect = unit_hour_side_effect
153-
154137
# Configure side effect for get_capacity_value
155-
# Capacity depends on unit, t, and step_k
156138
expected_capacity_gvar1 = 150
157139
expected_capacity_gvar2 = 250
140+
expected_capacity_gvar3 = 175
158141

159-
def capacity_side_effect(t, unit, sk, df):
160-
self.assertEqual(sk, step_k_test) # Check step_k is passed correctly
161-
self.assertIs(df, self.dummy_capacity_df) # Check df is passed correctly
162-
if unit == self.units[0] and t == 0:
142+
def capacity_side_effect(t_arg, unit_arg, sk_arg, df_arg):
143+
self.assertEqual(sk_arg, step_k_test)
144+
self.assertIs(df_arg, self.dummy_capacity_df)
145+
if unit_arg == self.units[0] and t_arg == 0:
163146
return expected_capacity_gvar1
164-
elif unit == self.units[1] and t == 1:
147+
elif unit_arg == self.units[1] and t_arg == 1:
165148
return expected_capacity_gvar2
166-
return 0 # Default, should not be hit with specific var names
149+
elif unit_arg == self.units[0] and t_arg == 2:
150+
return expected_capacity_gvar3
151+
return 0 # Default, should not be hit
167152

168153
mock_get_capacity_value.side_effect = capacity_side_effect
169154

170155
# Call the function
171-
# Pass the .values() if the function expects an iterable of Gurobi variables
172-
# The type hint is gp.tupledict, so we pass the dict itself.
173156
variable_func.update_var_with_variable_ub(
174157
variables=mock_variables_dict,
175158
step_k=step_k_test,
176159
capacity_df=self.dummy_capacity_df,
177160
)
178161

179162
# Assertions
180-
# Check get_unit_hour_from_varname calls
181-
mock_get_unit_hour_from_varname.assert_any_call(mock_gvar1.VarName)
182-
mock_get_unit_hour_from_varname.assert_any_call(mock_gvar2.VarName)
183-
self.assertEqual(mock_get_unit_hour_from_varname.call_count, 2)
184-
185163
# Check get_capacity_value calls
186-
mock_get_capacity_value.assert_any_call(
187-
0, self.units[0], step_k_test, self.dummy_capacity_df
188-
)
189-
mock_get_capacity_value.assert_any_call(
190-
1, self.units[1], step_k_test, self.dummy_capacity_df
191-
)
192-
self.assertEqual(mock_get_capacity_value.call_count, 2)
164+
# The calls are made based on the keys of mock_variables_dict
165+
expected_calls = [
166+
call(0, self.units[0], step_k_test, self.dummy_capacity_df),
167+
call(1, self.units[1], step_k_test, self.dummy_capacity_df),
168+
call(2, self.units[0], step_k_test, self.dummy_capacity_df),
169+
]
170+
mock_get_capacity_value.assert_has_calls(expected_calls, any_order=True)
171+
self.assertEqual(mock_get_capacity_value.call_count, len(mock_variables_dict))
193172

194173
# Check if variable upper bounds were updated
195174
self.assertEqual(mock_gvar1.ub, expected_capacity_gvar1)
196175
self.assertEqual(mock_gvar2.ub, expected_capacity_gvar2)
176+
self.assertEqual(mock_gvar3.ub, expected_capacity_gvar3)
197177

198-
@patch("pownet.optim_model.variable_func.get_edge_hour_from_varname")
199-
def test_update_flow_vars(self, mock_get_edge_hour_from_varname):
178+
def test_update_flow_vars(
179+
self,
180+
): # No external calls to mock within update_flow_vars directly
200181
"""Test the update_flow_vars function."""
201-
step_k_test = 2 # Using a different step_k to test the time indexing
182+
step_k_test = 2
202183
line_capacity_factor = 0.9
203184
hours_per_step = 24 # As defined in the source function
204185

205186
# Create mock Gurobi flow variables
206187
mock_flow_var1 = MagicMock()
207-
# Example VarName format, assuming some prefix like "flow_"
208-
mock_flow_var1.VarName = f"flow_{self.edges[0][0]}_{self.edges[0][1]}[0]"
209188
mock_flow_var1.ub = 0 # Initial ub
210189

211190
mock_flow_var2 = MagicMock()
212-
mock_flow_var2.VarName = (
213-
f"flow_{self.edges[1][0]}_{self.edges[1][1]}[2]" # t=2 for this var
214-
)
215191
mock_flow_var2.ub = 0
216192

193+
# Keys are (node1, node2, t) as expected by the function's iteration
217194
mock_flow_variables_dict = {
218-
(self.edges[0], 0): mock_flow_var1,
219-
(self.edges[1], 2): mock_flow_var2,
195+
(
196+
self.edges[0][0],
197+
self.edges[0][1],
198+
0,
199+
): mock_flow_var1, # ("node1", "node2", 0)
200+
(
201+
self.edges[1][0],
202+
self.edges[1][1],
203+
2,
204+
): mock_flow_var2, # ("node2", "node3", 2)
220205
}
221206

222-
# Configure side effect for get_edge_hour_from_varname
223-
def edge_hour_side_effect(var_name):
224-
if var_name == mock_flow_var1.VarName:
225-
return self.edges[0], 0 # (edge_tuple, time_in_step)
226-
elif var_name == mock_flow_var2.VarName:
227-
return self.edges[1], 2
228-
return None, None
229-
230-
mock_get_edge_hour_from_varname.side_effect = edge_hour_side_effect
231-
232207
# Call the function
233208
variable_func.update_flow_vars(
234-
flow_variables=mock_flow_variables_dict, # Pass dict, function iterates .values()
209+
flow_variables=mock_flow_variables_dict,
235210
step_k=step_k_test,
236211
capacity_df=self.flow_capacity_df,
237212
line_capacity_factor=line_capacity_factor,
238213
)
239214

240-
# Assertions
241-
# Check get_edge_hour_from_varname calls
242-
mock_get_edge_hour_from_varname.assert_any_call(mock_flow_var1.VarName)
243-
mock_get_edge_hour_from_varname.assert_any_call(mock_flow_var2.VarName)
244-
self.assertEqual(mock_get_edge_hour_from_varname.call_count, 2)
245-
246215
# Calculate expected capacities and UBs
247-
# For flow_var1: edge=self.edges[0], t=0
248-
time_idx1 = 0 + (step_k_test - 1) * hours_per_step # 0 + (2-1)*24 = 24
249-
expected_capacity1 = self.flow_capacity_df.loc[time_idx1, self.edges[0]]
216+
# For flow_var1: edge=self.edges[0] ("node1", "node2"), t=0
217+
key1_node1, key1_node2, key1_t = self.edges[0][0], self.edges[0][1], 0
218+
edge1 = (key1_node1, key1_node2)
219+
time_idx1 = key1_t + (step_k_test - 1) * hours_per_step # 0 + (2-1)*24 = 24
220+
expected_capacity1 = self.flow_capacity_df.loc[time_idx1, edge1]
250221
expected_ub1 = expected_capacity1 * line_capacity_factor
251222

252-
# For flow_var2: edge=self.edges[1], t=2
253-
time_idx2 = 2 + (step_k_test - 1) * hours_per_step # 2 + (2-1)*24 = 26
254-
expected_capacity2 = self.flow_capacity_df.loc[time_idx2, self.edges[1]]
223+
# For flow_var2: edge=self.edges[1] ("node2", "node3"), t=2
224+
key2_node1, key2_node2, key2_t = self.edges[1][0], self.edges[1][1], 2
225+
edge2 = (key2_node1, key2_node2)
226+
time_idx2 = key2_t + (step_k_test - 1) * hours_per_step # 2 + (2-1)*24 = 26
227+
expected_capacity2 = self.flow_capacity_df.loc[time_idx2, edge2]
255228
expected_ub2 = expected_capacity2 * line_capacity_factor
256229

257230
# Check if flow variable upper bounds were updated
258231
self.assertEqual(mock_flow_var1.ub, expected_ub1)
259232
self.assertEqual(mock_flow_var2.ub, expected_ub2)
260233

261234

262-
# This allows running the tests directly from the script
263235
if __name__ == "__main__":
264236
unittest.main()

0 commit comments

Comments
 (0)