Skip to content

Commit 906ec97

Browse files
committed
Refactor and patch only once
1 parent 10199b2 commit 906ec97

File tree

2 files changed

+68
-38
lines changed

2 files changed

+68
-38
lines changed

switch_model/utilities/load_data.py

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
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

1113

12-
def patch_to_allow_loading(cls: Type):
13-
def new_init(
14-
self, *args, input_file=None, input_column=None, input_optional=None, **kwargs
15-
):
16-
self.__old_init__(*args, **kwargs)
17-
if input_file is None:
18-
return
19-
20-
if input_optional is None:
21-
input_optional = "default" in kwargs
22-
23-
self.input_column = input_column
24-
self.input_optional = input_optional
14+
def register_component_for_loading(
15+
component, input_file, input_column, input_optional, **kwargs
16+
):
17+
"""
18+
Adds a component to the mapping
19+
"""
20+
# By default an input is optional if there is a default for that input already specified
21+
if input_optional is None:
22+
input_optional = "default" in kwargs
2523

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

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

3434

3535
def load_registered_inputs(switch_data, inputs_dir):
36+
"""
37+
Gets called to load all the inputs that are registered.
38+
"""
3639
for file, components in _registered_components.items():
3740
# We use lists since load_aug is going to convert to a list in any case
3841
params = [c for c in components if isinstance(c, Param)]
@@ -44,26 +47,31 @@ def load_registered_inputs(switch_data, inputs_dir):
4447
"This should not happen. Did you specify an input file for an element that is not a Set or Param?"
4548
)
4649

47-
kwargs = dict(filename=os.path.join(inputs_dir, file))
50+
kwargs = {"filename": os.path.join(inputs_dir, file)}
4851

4952
if len(index) > 1:
5053
raise Exception(
5154
f"Can't define multiple sets from the same file. {str(index)}"
5255
)
5356
elif len(index) == 1:
5457
index = index[0]
55-
optional = index.input_optional
58+
optional = (
59+
index.input_optional
60+
) # entire file is optional if the index is optional
5661
else:
5762
index = None
58-
optional = all(c.input_optional for c in components)
63+
optional = all(
64+
c.input_optional for c in components
65+
) # file is optional if each param is optional and no index
5966

6067
if len(params) == 0:
61-
kwargs["set"] = index
68+
kwargs["set"] = index # when only defining the index, we must use 'set'
6269
else:
6370
kwargs["param"] = params
6471
if index is not None:
6572
kwargs["index"] = index
6673

74+
# Load the data
6775
load_data(
6876
switch_data,
6977
optional=optional,

switch_model/utilities/patches.py

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
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+
13+
def patch_pyomo():
14+
global _patched_pyomo
15+
16+
if _patched_pyomo:
17+
return
18+
19+
# fix Pyomo issue #2019. Once PR #2020 gets released this will no longer be needed
20+
from pyomo.core.base.misc import _robust_sort_keyfcn
21+
22+
setattr(_robust_sort_keyfcn, "__call__", fixed_robust_sort_keyfcn)
23+
24+
# Patch Set and Param to allow specifying input file location (via input_file="...")
25+
extend_to_allow_loading(Set)
26+
extend_to_allow_loading(Param)
27+
28+
_patched_pyomo = True
29+
1130

1231
def fixed_robust_sort_keyfcn(self, val, use_key=True):
1332
"""Generate a tuple ( str(type_name), val ) for sorting the value.
@@ -54,15 +73,18 @@ def fixed_robust_sort_keyfcn(self, val, use_key=True):
5473
return _typename, id(val)
5574

5675

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

63-
# Patch Set and Param to allow specifying input file location (via input_file="...")
64-
patch_to_allow_loading(Set)
65-
patch_to_allow_loading(Param)
86+
cls.__old_init__ = cls.__init__
87+
cls.__init__ = new_init
6688

6789

6890
def replace_method(class_ref, method_name, new_source_code):

0 commit comments

Comments
 (0)