Skip to content

Commit 6db9e66

Browse files
committed
added rel_change and abs_change for change in design
1 parent 7cdba5b commit 6db9e66

2 files changed

Lines changed: 96 additions & 56 deletions

File tree

pyomo/contrib/doe/doe.py

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
compute_FIM_metrics,
5151
_SMALL_TOLERANCE_DEFINITENESS,
5252
snake_traversal_grid_sampling,
53+
update_model_from_suffix,
5354
)
5455

5556

@@ -1615,7 +1616,8 @@ def compute_FIM_full_factorial(
16151616
def compute_FIM_factorial(
16161617
self,
16171618
model=None,
1618-
design_values: dict = None,
1619+
abs_change: list = None,
1620+
rel_change: list = None,
16191621
method="sequential",
16201622
change_one_design_at_a_time=True,
16211623
file_name: str = None,
@@ -1629,6 +1631,14 @@ def compute_FIM_factorial(
16291631
----------
16301632
model : DoE model, optional
16311633
The model to perform the full factorial exploration on. Default: None
1634+
# TODO: Update doc string for absolute and relative change
1635+
abs_change : list, optional
1636+
Absolute change in the design variable values. Default: None.
1637+
If provided, will use this value to generate the design values.
1638+
If not provided, will use the `design_values` parameter.
1639+
rel_change : list, optional
1640+
Relative change in the design variable values. Default: None.
1641+
If provided, will use this value to generate the design values.
16321642
design_values : dict,
16331643
dict of lists or other array-like objects, of the form {"var_name": <var_values>}. Default: None.
16341644
The `design_values` should have the key(s) passed as strings that is a
@@ -1687,35 +1697,47 @@ def compute_FIM_factorial(
16871697
).clone()
16881698
model = self.factorial_model
16891699

1690-
if not design_values:
1691-
raise ValueError(
1692-
"design_values must be provided as a dictionary of array-like objects "
1693-
"in the form {<'var_name'>: <var_values>}."
1694-
)
1695-
1696-
# Check whether the design_ranges keys are in the experiment_inputs
1697-
design_keys = set(design_values.keys())
1698-
map_keys = set([k.name for k in model.experiment_inputs.keys()])
1699-
if not design_keys.issubset(map_keys):
1700-
incorrect_given_keys = design_keys - map_keys
1701-
suggested_keys = map_keys - design_keys
1702-
raise ValueError(
1703-
f"design_values keys: {incorrect_given_keys} are incorrect."
1704-
f"The keys should be from the following keys: {suggested_keys}."
1705-
)
1706-
17071700
# Get the design map keys that match the design_values keys
1708-
design_map_keys = [
1709-
k for k in model.experiment_inputs.keys() if k.name in design_values.keys()
1710-
]
1701+
# design_map_keys = [
1702+
# k for k in model.experiment_inputs.keys() if k.name in design_values.keys()
1703+
# ]
17111704
# This ensures that the order of the design_values keys matches the order of the
17121705
# design_map_keys so that design_point can be constructed correctly in the loop.
17131706
# TODO: define an Enum to add different sensitivity analysis sequences
1714-
des_ranges = [design_values[k.name] for k in design_map_keys]
1707+
# des_ranges = [design_values[k.name] for k in design_map_keys]
1708+
1709+
design_keys = [k for k in model.experiment_inputs.keys()]
1710+
1711+
design_values = []
1712+
for i, comp in enumerate(design_keys):
1713+
lb = comp.lb
1714+
ub = comp.ub
1715+
if lb is None or ub is None:
1716+
raise ValueError(f"{comp.name} does not have a lower or upper bound.")
1717+
1718+
if abs_change[i] is None and rel_change[i] is None:
1719+
n_des = 5 # Default number of points in the design value
1720+
des_val = np.linspace(lb, ub, n_des)
1721+
1722+
elif abs_change[i] is not None and rel_change[i] is not None:
1723+
des_val = []
1724+
del_val = comp.lb * rel_change[i] + abs_change[i]
1725+
if del_val == 0:
1726+
raise ValueError(
1727+
f"Design variable {comp.name} has no change in value - check "
1728+
"abs_change and rel_change values."
1729+
)
1730+
val = lb
1731+
while val <= ub:
1732+
des_val.append(val)
1733+
val += del_val
1734+
1735+
design_values.append(des_val)
1736+
17151737
if change_one_design_at_a_time:
1716-
factorial_points = snake_traversal_grid_sampling(*des_ranges)
1738+
factorial_points = snake_traversal_grid_sampling(*design_values)
17171739
else:
1718-
factorial_points = product(*des_ranges)
1740+
factorial_points = product(*design_values)
17191741

17201742
factorial_points_list = list(factorial_points)
17211743

@@ -1747,7 +1769,7 @@ def compute_FIM_factorial(
17471769
for design_point in factorial_points_list:
17481770
# Fix design variables at fixed experimental design point
17491771
for i in range(len(design_point)):
1750-
design_map_keys[i].fix(design_point[i])
1772+
design_keys[i].fix(design_point[i])
17511773

17521774
# Timing and logging objects
17531775
self.logger.info(f"=======Iteration Number: {curr_point} =======")
@@ -1817,6 +1839,23 @@ def compute_FIM_factorial(
18171839
"FIM_all": FIM_all.tolist(), # Save all FIMs
18181840
}
18191841
)
1842+
if self.tee:
1843+
exclude_keys = {
1844+
"total_points",
1845+
"success_counts",
1846+
"failure_counts",
1847+
"FIM_all",
1848+
}
1849+
dict_for_df = {
1850+
k: v for k, v in factorial_results.items() if k not in exclude_keys
1851+
}
1852+
res_df = pd.DataFrame(dict_for_df)
1853+
print("\n\n=========Factorial results DataFrame===========")
1854+
print(res_df)
1855+
print("\n\n")
1856+
print("Total points:", total_points)
1857+
print("Success counts:", success_count)
1858+
print("Failure counts:", failure_count)
18201859

18211860
self.factorial_results = factorial_results
18221861

pyomo/contrib/doe/utils.py

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -91,37 +91,38 @@ def rescale_FIM(FIM, param_vals):
9191
scaled_FIM = np.multiply(FIM, scaling_mat)
9292
return scaled_FIM
9393

94-
# TODO: Add swapping parameters for variables helper function
95-
# def get_parameters_from_suffix(suffix, fix_vars=False):
96-
# """
97-
# Finds the Params within the suffix provided. It will also check to see
98-
# if there are Vars in the suffix provided. ``fix_vars`` will indicate
99-
# if we should fix all the Vars in the set or not.
100-
#
101-
# Parameters
102-
# ----------
103-
# suffix: pyomo Suffix object, contains the components to be checked
104-
# as keys
105-
# fix_vars: boolean, whether or not to fix the Vars, default = False
106-
#
107-
# Returns
108-
# -------
109-
# param_list: list of Param
110-
# """
111-
# param_list = []
112-
#
113-
# # FIX THE MODEL TREE ISSUE WHERE I GET base_model.<param> INSTEAD OF <param>
114-
# # Check keys if they are Param or Var. Fix the vars if ``fix_vars`` is True
115-
# for k, v in suffix.items():
116-
# if isinstance(k, ParamData):
117-
# param_list.append(k.name)
118-
# elif isinstance(k, VarData):
119-
# if fix_vars:
120-
# k.fix()
121-
# else:
122-
# pass # ToDo: Write error for suffix keys that aren't ParamData or VarData
123-
#
124-
# return param_list
94+
95+
# TODO: Add swapping parameters for variables helper function
96+
# def get_parameters_from_suffix(suffix, fix_vars=False):
97+
# """
98+
# Finds the Params within the suffix provided. It will also check to see
99+
# if there are Vars in the suffix provided. ``fix_vars`` will indicate
100+
# if we should fix all the Vars in the set or not.
101+
#
102+
# Parameters
103+
# ----------
104+
# suffix: pyomo Suffix object, contains the components to be checked
105+
# as keys
106+
# fix_vars: boolean, whether or not to fix the Vars, default = False
107+
#
108+
# Returns
109+
# -------
110+
# param_list: list of Param
111+
# """
112+
# param_list = []
113+
#
114+
# # FIX THE MODEL TREE ISSUE WHERE I GET base_model.<param> INSTEAD OF <param>
115+
# # Check keys if they are Param or Var. Fix the vars if ``fix_vars`` is True
116+
# for k, v in suffix.items():
117+
# if isinstance(k, ParamData):
118+
# param_list.append(k.name)
119+
# elif isinstance(k, VarData):
120+
# if fix_vars:
121+
# k.fix()
122+
# else:
123+
# pass # ToDo: Write error for suffix keys that aren't ParamData or VarData
124+
#
125+
# return param_list
125126

126127

127128
# Adding utility to update parameter values in a model based on the suffix

0 commit comments

Comments
 (0)