Skip to content

Commit 5dd96a6

Browse files
committed
Refactor and patch only once
1 parent b6e7745 commit 5dd96a6

File tree

2 files changed

+56
-34
lines changed

2 files changed

+56
-34
lines changed

switch_model/utilities/load_data.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
1+
"""
2+
This file handles how data is loaded into SWITCH from the .csv files
3+
"""
14
import os
2-
from typing import Type
35

46
from pyomo.core.base.set import UnknownSetDimen
57
from pyomo.environ import *
68

7-
# Mapping of file names to components to load from that file.
8-
# Ordered dict to ensure we are creating our components in the right order
9+
# Maps file names to Pyomo components.
10+
# The mapping indicates which components should be loaded with data from which files.
911
_registered_components = {}
1012

11-
def patch_to_allow_loading(cls: Type):
12-
def new_init(self, *args, input_file=None, input_column=None, input_optional=None, **kwargs):
13-
self.__old_init__(*args, **kwargs)
14-
if input_file is None:
15-
return
1613

17-
if input_optional is None:
18-
input_optional = "default" in kwargs
19-
20-
self.input_column = input_column
21-
self.input_optional = input_optional
14+
def register_component_for_loading(component, input_file, input_column, input_optional, **kwargs):
15+
"""
16+
Adds a component to the mapping
17+
"""
18+
# By default an input is optional if there is a default for that input already specified
19+
if input_optional is None:
20+
input_optional = "default" in kwargs
2221

23-
if input_file not in _registered_components:
24-
_registered_components[input_file] = [self]
25-
else:
26-
_registered_components[input_file].append(self)
22+
# Add the column and optional parameters to the component
23+
component.input_column = input_column
24+
component.input_optional = input_optional
2725

28-
cls.__old_init__ = cls.__init__
29-
cls.__init__ = new_init
26+
# Add the component to the mapping
27+
if input_file not in _registered_components:
28+
_registered_components[input_file] = [component]
29+
else:
30+
_registered_components[input_file].append(component)
3031

3132

3233
def load_registered_inputs(switch_data, inputs_dir):
34+
"""
35+
Gets called to load all the inputs that are registered.
36+
"""
3337
for file, components in _registered_components.items():
3438
# We use lists since load_aug is going to convert to a list in any case
3539
params = [c for c in components if isinstance(c, Param)]
@@ -40,24 +44,25 @@ def load_registered_inputs(switch_data, inputs_dir):
4044
raise Exception(
4145
"This should not happen. Did you specify an input file for an element that is not a Set or Param?")
4246

43-
kwargs = dict(filename=os.path.join(inputs_dir, file))
47+
kwargs = {'filename': os.path.join(inputs_dir, file)}
4448

4549
if len(index) > 1:
4650
raise Exception(f"Can't define multiple sets from the same file. {str(index)}")
4751
elif len(index) == 1:
4852
index = index[0]
49-
optional = index.input_optional
53+
optional = index.input_optional # entire file is optional if the index is optional
5054
else:
5155
index = None
52-
optional = all(c.input_optional for c in components)
56+
optional = all(c.input_optional for c in components) # file is optional if each param is optional and no index
5357

5458
if len(params) == 0:
55-
kwargs["set"] = index
59+
kwargs["set"] = index # when only defining the index, we must use 'set'
5660
else:
5761
kwargs["param"] = params
5862
if index is not None:
5963
kwargs["index"] = index
6064

65+
# Load the data
6166
load_data(switch_data, optional=optional, auto_select=True, optional_params=optional_params, **kwargs)
6267

6368
# Remove all the elements to reset the dictionary

switch_model/utilities/patches.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,29 @@
11
import inspect
22
import textwrap
33
import types
4+
from typing import Type
45

5-
import pyomo.version
6-
from pyomo.core.base.misc import _robust_sort_keyfcn
7-
8-
from switch_model.utilities.load_data import patch_to_allow_loading
96
from pyomo.environ import Set, Param
107

8+
from switch_model.utilities.load_data import register_component_for_loading
9+
10+
_patched_pyomo = False
11+
12+
def patch_pyomo():
13+
global _patched_pyomo
14+
15+
if _patched_pyomo:
16+
return
17+
18+
# fix Pyomo issue #2019. Once PR #2020 gets released this will no longer be needed
19+
from pyomo.core.base.misc import _robust_sort_keyfcn
20+
setattr(_robust_sort_keyfcn, "__call__", fixed_robust_sort_keyfcn)
21+
22+
# Patch Set and Param to allow specifying input file location (via input_file="...")
23+
extend_to_allow_loading(Set)
24+
extend_to_allow_loading(Param)
25+
26+
_patched_pyomo = True
1127

1228
def fixed_robust_sort_keyfcn(self, val, use_key=True):
1329
"""Generate a tuple ( str(type_name), val ) for sorting the value.
@@ -53,14 +69,15 @@ def fixed_robust_sort_keyfcn(self, val, use_key=True):
5369
else:
5470
return _typename, id(val)
5571

56-
def patch_pyomo():
57-
# fix Pyomo issue #2019. Once PR #2020 gets released this will no longer be needed
58-
from pyomo.core.base.misc import _robust_sort_keyfcn
59-
setattr(_robust_sort_keyfcn, "__call__", fixed_robust_sort_keyfcn)
72+
def extend_to_allow_loading(cls: Type):
73+
def new_init(self, *args, input_file=None, input_column=None, input_optional=None, **kwargs):
74+
self.__old_init__(*args, **kwargs)
75+
if input_file is not None:
76+
register_component_for_loading(self, input_file, input_column, input_optional, **kwargs)
77+
78+
cls.__old_init__ = cls.__init__
79+
cls.__init__ = new_init
6080

61-
# Patch Set and Param to allow specifying input file location (via input_file="...")
62-
patch_to_allow_loading(Set)
63-
patch_to_allow_loading(Param)
6481

6582
def replace_method(class_ref, method_name, new_source_code):
6683
"""

0 commit comments

Comments
 (0)