Skip to content

Commit bdcfa4f

Browse files
authored
Merge pull request #3635 from slilonfe5/parmest-bug-fix
Bug fixes in the current parmest.py and example files
2 parents 9cff668 + cee2826 commit bdcfa4f

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

pyomo/contrib/parmest/examples/semibatch/semibatch.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,20 @@ def label_model(self):
284284

285285
m = self.model
286286

287+
m.experiment_outputs = Suffix(direction=Suffix.LOCAL)
288+
m.experiment_outputs.update(
289+
(m.Ca[t], self.data["Ca_meas"][f"{t}"]) for t in m.measT
290+
)
291+
m.experiment_outputs.update(
292+
(m.Cb[t], self.data["Cb_meas"][f"{t}"]) for t in m.measT
293+
)
294+
m.experiment_outputs.update(
295+
(m.Cc[t], self.data["Cc_meas"][f"{t}"]) for t in m.measT
296+
)
297+
m.experiment_outputs.update(
298+
(m.Tr[t], self.data["Tr_meas"][f"{t}"]) for t in m.measT
299+
)
300+
287301
m.unknown_parameters = Suffix(direction=Suffix.LOCAL)
288302
m.unknown_parameters.update(
289303
(k, ComponentUID(k)) for k in [m.k1, m.k2, m.E1, m.E2]

pyomo/contrib/parmest/parmest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,13 +284,13 @@ def __init__(
284284
try:
285285
outputs = [k.name for k, v in model.experiment_outputs.items()]
286286
except:
287-
RuntimeError(
287+
raise RuntimeError(
288288
'Experiment list model does not have suffix ' + '"experiment_outputs".'
289289
)
290290
try:
291291
params = [k.name for k, v in model.unknown_parameters.items()]
292292
except:
293-
RuntimeError(
293+
raise RuntimeError(
294294
'Experiment list model does not have suffix ' + '"unknown_parameters".'
295295
)
296296

pyomo/contrib/parmest/tests/test_parmest.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,39 @@ def SSE(model):
8080
exp_list, obj_function=SSE, solver_options=solver_options, tee=True
8181
)
8282

83+
def test_parmest_exception(self):
84+
"""
85+
Test the exception raised by parmest when the "experiment_outputs"
86+
attribute is not defined in the model
87+
"""
88+
from pyomo.contrib.parmest.examples.rooney_biegler.rooney_biegler import (
89+
RooneyBieglerExperiment,
90+
)
91+
92+
# create an instance of the RooneyBieglerExperiment class
93+
# without the "experiment_outputs" attribute
94+
class RooneyBieglerExperimentException(RooneyBieglerExperiment):
95+
def label_model(self):
96+
m = self.model
97+
98+
# add the unknown parameters
99+
m.unknown_parameters = pyo.Suffix(direction=pyo.Suffix.LOCAL)
100+
m.unknown_parameters.update(
101+
(k, pyo.ComponentUID(k)) for k in [m.asymptote, m.rate_constant]
102+
)
103+
104+
# create an experiment list
105+
exp_list = []
106+
for i in range(self.data.shape[0]):
107+
exp_list.append(RooneyBieglerExperimentException(self.data.loc[i, :]))
108+
109+
# check the exception raised by parmest due to not defining
110+
# the "experiment_outputs"
111+
with self.assertRaises(RuntimeError) as context:
112+
parmest.Estimator(exp_list, obj_function="SSE", tee=True)
113+
114+
self.assertIn("experiment_outputs", str(context.exception))
115+
83116
def test_theta_est(self):
84117
objval, thetavals = self.pest.theta_est()
85118

@@ -816,6 +849,22 @@ def label_model(self):
816849

817850
m = self.model
818851

852+
if isinstance(self.data, pd.DataFrame):
853+
meas_time_points = self.data.index
854+
else:
855+
meas_time_points = list(self.data["ca"].keys())
856+
857+
m.experiment_outputs = pyo.Suffix(direction=pyo.Suffix.LOCAL)
858+
m.experiment_outputs.update(
859+
(m.ca[t], self.data["ca"][t]) for t in meas_time_points
860+
)
861+
m.experiment_outputs.update(
862+
(m.cb[t], self.data["cb"][t]) for t in meas_time_points
863+
)
864+
m.experiment_outputs.update(
865+
(m.cc[t], self.data["cc"][t]) for t in meas_time_points
866+
)
867+
819868
m.unknown_parameters = pyo.Suffix(direction=pyo.Suffix.LOCAL)
820869
m.unknown_parameters.update(
821870
(k, pyo.ComponentUID(k)) for k in [m.k1, m.k2]
@@ -885,6 +934,51 @@ def get_labeled_model(self):
885934
self.m_df = ABC_model(data_df)
886935
self.m_dict = ABC_model(data_dict)
887936

937+
# create an instance of the ReactorDesignExperimentDAE class
938+
# without the "unknown_parameters" attribute
939+
class ReactorDesignExperimentException(ReactorDesignExperimentDAE):
940+
def label_model(self):
941+
942+
m = self.model
943+
944+
if isinstance(self.data, pd.DataFrame):
945+
meas_time_points = self.data.index
946+
else:
947+
meas_time_points = list(self.data["ca"].keys())
948+
949+
m.experiment_outputs = pyo.Suffix(direction=pyo.Suffix.LOCAL)
950+
m.experiment_outputs.update(
951+
(m.ca[t], self.data["ca"][t]) for t in meas_time_points
952+
)
953+
m.experiment_outputs.update(
954+
(m.cb[t], self.data["cb"][t]) for t in meas_time_points
955+
)
956+
m.experiment_outputs.update(
957+
(m.cc[t], self.data["cc"][t]) for t in meas_time_points
958+
)
959+
960+
# create an experiment list without the "unknown_parameters" attribute
961+
exp_list_df_no_params = [ReactorDesignExperimentException(data_df)]
962+
exp_list_dict_no_params = [ReactorDesignExperimentException(data_dict)]
963+
964+
self.exp_list_df_no_params = exp_list_df_no_params
965+
self.exp_list_dict_no_params = exp_list_dict_no_params
966+
967+
def test_parmest_exception(self):
968+
"""
969+
Test the exception raised by parmest when the "unknown_parameters"
970+
attribute is not defined in the model
971+
"""
972+
with self.assertRaises(RuntimeError) as context:
973+
parmest.Estimator(self.exp_list_df_no_params, obj_function="SSE")
974+
975+
self.assertIn("unknown_parameters", str(context.exception))
976+
977+
with self.assertRaises(RuntimeError) as context:
978+
parmest.Estimator(self.exp_list_dict_no_params, obj_function="SSE")
979+
980+
self.assertIn("unknown_parameters", str(context.exception))
981+
888982
def test_dataformats(self):
889983
obj1, theta1 = self.pest_df.theta_est()
890984
obj2, theta2 = self.pest_dict.theta_est()

0 commit comments

Comments
 (0)