Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvements to scaling API #1507

Merged
merged 87 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
528a4f7
Adding infrastructure to support ipopt_v2
andrewlee94 Jun 14, 2024
0faabba
Moving core/util to ipopt_v2
andrewlee94 Jun 14, 2024
47d9d73
Moving MH initializer to ipopt_v2
andrewlee94 Jun 15, 2024
47beac6
Fixing pint version issue
andrewlee94 Jun 17, 2024
c39f256
Set TSA to use old IPOPT interface
andrewlee94 Jun 17, 2024
04f1463
Fixing conflict
andrewlee94 Jun 17, 2024
3ce08dd
Trying to resolve Windows failures
andrewlee94 Jun 17, 2024
4aa1405
Working on platofrm dependent failure
andrewlee94 Jun 17, 2024
7353472
BTInitializer with presolve
andrewlee94 Jun 20, 2024
e88bd83
Merge branch 'main' of https://github.com/IDAES/idaes-pse into presolve
andrewlee94 Jun 20, 2024
d5135f4
Moving last bits of core code to ipopt_v2
andrewlee94 Jun 20, 2024
9ccc8b4
Starting on idaes/models
andrewlee94 Jun 20, 2024
9423501
Removing ma57_automatic_scaling default and updating idaes/models/con…
andrewlee94 Jun 20, 2024
6754964
idaes/model/properties part 1
andrewlee94 Jun 20, 2024
f6079ca
Remaining parts of idaes/models/proeprties
andrewlee94 Jun 20, 2024
ad475fd
Fixing typo
andrewlee94 Jun 20, 2024
dda16b3
Switching idaes/models/unit_models to ipopt_v2
andrewlee94 Jun 21, 2024
bc8e411
Attempt to work around HXLC issues for now
andrewlee94 Jun 21, 2024
4273e24
Some clean up
andrewlee94 Jun 21, 2024
542914a
Switching modular properties initializer to solver indexed blocks
andrewlee94 Jun 21, 2024
6578d01
Merge branch 'modular_properties_init' into presolve
andrewlee94 Jun 21, 2024
84e9d69
Addressing comments
andrewlee94 Jun 21, 2024
c3615a1
Recovering from previous branch
andrewlee94 Jun 21, 2024
6a7750c
Merge branch 'presolve' into autoscaling_rebase
andrewlee94 Jun 21, 2024
8be4d5a
Some clean up
andrewlee94 Jun 21, 2024
dbdbdd4
Adding ScalerBase class and tests
andrewlee94 Jun 24, 2024
adc2809
Working on CustomScalerBase
andrewlee94 Jun 24, 2024
d9f1904
Nominal value constraint scaling
andrewlee94 Jun 25, 2024
5f4fe46
Adding some initial integration tests for scaling
andrewlee94 Jun 25, 2024
72a183d
Some more nominal magnitude scaling approaches
andrewlee94 Jun 25, 2024
a6ef9cb
Merge pull request #21 from andrewlee94/custom_scalers_proto
andrewlee94 Jun 25, 2024
a12cb95
Prototyping pseudojacobian scaler
andrewlee94 Jun 26, 2024
b3aafb0
Merge branch 'main' into autoscaling
andrewlee94 Jun 26, 2024
c51672f
Trying to debug pseudojacobian
andrewlee94 Jun 26, 2024
861ef58
Removing unnecessary import
andrewlee94 Jun 26, 2024
3805792
Merge branch 'main' of https://github.com/IDAES/idaes-pse
andrewlee94 Jun 26, 2024
fbedaf4
Merge branch 'main' into autoscaling
andrewlee94 Jun 26, 2024
76bec99
Addressing pylint issues
andrewlee94 Jun 26, 2024
eec789e
Merge branch 'autoscaling' into custom_scalers_proto
andrewlee94 Jun 26, 2024
d80eed6
Cleaning up nominal jacobian
andrewlee94 Jun 26, 2024
c88879e
More methods for CustomScalerBase
andrewlee94 Jun 27, 2024
5a29597
Prototyping Gibbs reactor scaler
andrewlee94 Jun 27, 2024
154a622
Gibbs reactor constraint scaling
andrewlee94 Jun 27, 2024
a6d61fa
Working on testing and profiling
andrewlee94 Jun 28, 2024
86faf86
Refining Gibbs scaler
andrewlee94 Jun 30, 2024
ac2b639
Refining nominal value walker
andrewlee94 Jun 30, 2024
f3f6330
Fixing walker tests
andrewlee94 Jul 1, 2024
ce8c202
Testing GibbsScaler with initialization
andrewlee94 Jul 1, 2024
05537fd
Fixing auto norm scaling on indexed blocks
andrewlee94 Jul 1, 2024
3c302e6
Testing scaling profiler
andrewlee94 Jul 2, 2024
937e596
Fixing typos
andrewlee94 Jul 2, 2024
ef9c5e9
Fixing pylint issue
andrewlee94 Jul 2, 2024
6662fc7
Imrpoving some doc strings
andrewlee94 Jul 5, 2024
0308f1e
Merge branch 'main' into autoscaling
andrewlee94 Jul 22, 2024
ec49414
Apply suggestions from code review
andrewlee94 Aug 6, 2024
f7eda46
Merge branch 'main' into autoscaling
andrewlee94 Aug 15, 2024
e3b169d
Fixing issue with autoscaling vars with value None
andrewlee94 Aug 15, 2024
1370bbe
Merge branch 'autoscaling' of https://github.com/andrewlee94/idaes-ps…
andrewlee94 Aug 15, 2024
a5de0b7
Adding profiler to __init__
andrewlee94 Aug 15, 2024
0964c7a
Fixing name for RSS method
andrewlee94 Aug 15, 2024
0af66e1
Merge branch 'main' of https://github.com/IDAES/idaes-pse into autosc…
andrewlee94 Aug 26, 2024
0f6d262
Fixing import of pyomo.environ
andrewlee94 Aug 26, 2024
bd1b6aa
Allowing default scaling for indexed components
andrewlee94 Aug 26, 2024
0cad4ed
Adding catch for critical solver failure in profiler
andrewlee94 Aug 27, 2024
3b6ae69
Merge branch 'main' into autoscaling
andrewlee94 Sep 30, 2024
f3940a1
Merge branch 'autoscaling' of https://github.com/andrewlee94/idaes-ps…
andrewlee94 Sep 30, 2024
c71fbd1
Starting on docs
andrewlee94 Sep 30, 2024
10fbf3d
Finishing docs and unifiying method names
andrewlee94 Oct 1, 2024
794f1ed
Profiler report methods and docs
andrewlee94 Oct 2, 2024
21ef587
Fixing typos
andrewlee94 Oct 2, 2024
2d1dd54
Pylint: fix unnecessary f-string
andrewlee94 Oct 2, 2024
19212fa
Working on equilibrium reactor scaler
andrewlee94 Oct 4, 2024
8f56b88
Finishing tests for equilibrium reactor scaler
andrewlee94 Oct 4, 2024
1e3163f
Fixing conflicts
andrewlee94 Oct 11, 2024
1d55e06
Updaing requil scaler
andrewlee94 Oct 11, 2024
fb5d2a9
Fixing typo
andrewlee94 Oct 11, 2024
1f200db
Addressing pylint issue
andrewlee94 Oct 11, 2024
c8e7408
Improving guess for heat duty scaling
andrewlee94 Oct 11, 2024
148c2f3
Updating test value for heat duty scaling
andrewlee94 Oct 11, 2024
c18f464
Minor fix
andrewlee94 Oct 18, 2024
2aa07a0
Merge branch 'main' into requil_scaling
andrewlee94 Oct 19, 2024
2759010
Adding Enum to __init__
andrewlee94 Oct 19, 2024
7f32d73
Adding doc strings for saponification scalers
andrewlee94 Oct 20, 2024
cd82ad8
Fixing typo
andrewlee94 Oct 20, 2024
1e7b74c
Minor clean up
andrewlee94 Oct 22, 2024
4808df4
Fixing conflict
andrewlee94 Oct 22, 2024
e45968b
Removing need for string constants
andrewlee94 Oct 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 10 additions & 19 deletions idaes/core/scaling/custom_scaler_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,8 +554,7 @@ def propagate_state_scaling(

def call_submodel_scaler_method(
self,
model,
submodel: str,
submodel,
method: str,
submodel_scalers: ComponentMap = None,
overwrite: bool = False,
Expand All @@ -567,55 +566,47 @@ def call_submodel_scaler_method(
default scaler for the submodel is used.

Args:
model: parent model of submodel
submodel: local name of submodel to be scaled as str
submodel: submodel to be scaled
submodel_scalers: user provided ComponentMap of Scalers to use for submodels
method: name of method to call from submodel (as string)
overwrite: whether to overwrite existing scaling factors

Returns:
None
"""
# Get actual submodel object from name
# For this method, we have to use the component name as the Scaler is written
# before the model is constructed.
sm_obj = model.find_component(submodel)

if submodel_scalers is None:
submodel_scalers = {}

# Iterate over indices of submodel
for smdata in sm_obj.values():
for smdata in submodel.values():
# Get Scaler for submodel
if sm_obj in submodel_scalers:
scaler = submodel_scalers[sm_obj]
if submodel in submodel_scalers:
scaler = submodel_scalers[submodel]
if callable(scaler):
# Check to see if Scaler is callable - this implies it is a class and not an instance
# Call the class to create an instance
scaler = scaler()
_log.debug(f"Using user-defined Scaler for {model}.{submodel}.")
_log.debug(f"Using user-defined Scaler for {submodel}.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to give human readable output, or is it going to be some Pyomo thing in brackets?

Consider using submodel.name

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will end up being submodel.name - it is not obvious but the f-string magic casts it to a string.

else:
try:
scaler = smdata.default_scaler
_log.debug(f"Using default Scaler for {model}.{submodel}.")
_log.debug(f"Using default Scaler for {submodel}.")
except AttributeError:
_log.debug(
f"No default Scaler set for {model}.{submodel}. Cannot call {method}."
f"No default Scaler set for {submodel}. Cannot call {method}."
)
return
if scaler is not None:
scaler = scaler()
else:
_log.debug(
f"No Scaler found for {model}.{submodel}. Cannot call {method}."
)
_log.debug(f"No Scaler found for {submodel}. Cannot call {method}.")

# If a Scaler is found, call desired method
if scaler is not None:
try:
smeth = getattr(scaler, method)
except AttributeError:
raise AttributeError(
f"Scaler for {model}.{submodel} does not have a method named {method}."
f"Scaler for {submodel} does not have a method named {method}."
)
smeth(smdata, overwrite=overwrite)
44 changes: 8 additions & 36 deletions idaes/core/scaling/tests/test_custom_scaler_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,15 +608,12 @@ def test_call_submodel_scaler_method_no_scaler(self, caplog):
m.b = Block([1, 2, 3])

sb = CustomScalerBase()
sb.call_submodel_scaler_method(m, "b", method="dummy_method", overwrite=True)
sb.call_submodel_scaler_method(m.b, method="dummy_method", overwrite=True)

for bd in m.b.values():
assert not hasattr(bd, "_dummy_scaler_test")

assert (
"No default Scaler set for unknown.b. Cannot call dummy_method."
in caplog.text
)
assert "No default Scaler set for b. Cannot call dummy_method." in caplog.text
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if only referencing dummy_method in error message may confuse maintainer in the future

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a suggestion for a better message?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"No default Scaler set for b. Cannot call dummy_method created for testing purposes."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message is generated dynamically using the name of the method the user asked for. In this test case, the method I asked for was named "dummy_method", but a user would see the name of the method they specified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I think it's fine


@pytest.mark.unit
def test_call_submodel_scaler_method_default_scaler(self, caplog):
Expand All @@ -629,12 +626,12 @@ def test_call_submodel_scaler_method_default_scaler(self, caplog):
bd.default_scaler = DummyScaler

sb = CustomScalerBase()
sb.call_submodel_scaler_method(m, "b", method="dummy_method", overwrite=True)
sb.call_submodel_scaler_method(m.b, method="dummy_method", overwrite=True)

for bd in m.b.values():
assert bd._dummy_scaler_test

assert "Using default Scaler for unknown.b." in caplog.text
assert "Using default Scaler for b." in caplog.text

@pytest.mark.unit
def test_call_submodel_scaler_method_user_scaler(self, caplog):
Expand All @@ -649,8 +646,7 @@ def test_call_submodel_scaler_method_user_scaler(self, caplog):

sb = CustomScalerBase()
sb.call_submodel_scaler_method(
m,
"b",
m.b,
method="dummy_method",
submodel_scalers=scaler_map,
overwrite=False,
Expand All @@ -659,7 +655,7 @@ def test_call_submodel_scaler_method_user_scaler(self, caplog):
for bd in m.b.values():
assert not bd._dummy_scaler_test

assert "Using user-defined Scaler for unknown.b." in caplog.text
assert "Using user-defined Scaler for b." in caplog.text

@pytest.mark.unit
def test_call_submodel_scaler_method_user_scaler_class(self, caplog):
Expand All @@ -674,8 +670,7 @@ def test_call_submodel_scaler_method_user_scaler_class(self, caplog):

sb = CustomScalerBase()
sb.call_submodel_scaler_method(
m,
"b",
m.b,
method="dummy_method",
submodel_scalers=scaler_map,
overwrite=False,
Expand All @@ -684,27 +679,4 @@ def test_call_submodel_scaler_method_user_scaler_class(self, caplog):
for bd in m.b.values():
assert not bd._dummy_scaler_test

assert "Using user-defined Scaler for unknown.b." in caplog.text

@pytest.mark.unit
def test_call_submodel_scaler_method_invalid_method(self):
# Dummy up a nested model
m = ConcreteModel()
m.b = Block([1, 2, 3])

scaler_map = ComponentMap()
scaler_map[m.b] = DummyScaler()

sb = CustomScalerBase()

with pytest.raises(
AttributeError,
match="Scaler for unknown.b does not have a method named foo.",
):
sb.call_submodel_scaler_method(
m,
"b",
method="foo",
submodel_scalers=scaler_map,
overwrite=False,
)
assert "Using user-defined Scaler for b." in caplog.text
22 changes: 9 additions & 13 deletions idaes/models/unit_models/equilibrium_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ def variable_scaling_routine(
"""
# Call scaling methods for sub-models
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_in",
submodel=model.control_volume.properties_in,
method="variable_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
Expand All @@ -89,15 +88,13 @@ def variable_scaling_routine(
)

self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_out",
submodel=model.control_volume.properties_out,
method="variable_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
)
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.reactions",
submodel=model.control_volume.reactions,
method="variable_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
Expand All @@ -121,6 +118,8 @@ def variable_scaling_routine(
for t in model.flowsheet().time:
h_in = 0
for p in model.control_volume.properties_in.phase_list:
# The expression for enthalpy flow might include multiple terms,
# so we will sum over all the terms provided
h_in += sum(
self.get_expression_nominal_values(
model.control_volume.properties_in[
Expand All @@ -130,7 +129,7 @@ def variable_scaling_routine(
)
# Scale for heat is general one order of magnitude less than enthalpy flow
self.set_variable_scaling_factor(
model.control_volume.heat[t], 1 / (0.1 * h_in)
model.control_volume.heat[t], abs(1 / (0.1 * h_in))
)

def constraint_scaling_routine(
Expand All @@ -152,22 +151,19 @@ def constraint_scaling_routine(
"""
# Call scaling methods for sub-models
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_in",
submodel=model.control_volume.properties_in,
method="constraint_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
)
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_out",
submodel=model.control_volume.properties_out,
method="constraint_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
)
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.reactions",
submodel=model.control_volume.reactions,
method="constraint_scaling_routine",
submodel_scalers=submodel_scalers,
overwrite=overwrite,
Expand Down
12 changes: 4 additions & 8 deletions idaes/models/unit_models/gibbs_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,14 @@ def variable_scaling_routine(
# Step 1b: Call Scalers for state blocks
# Inlet properties
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_in",
submodel=model.control_volume.properties_in,
submodel_scalers=submodel_scalers,
method="variable_scaling_routine",
overwrite=overwrite,
)
# Outlet properties
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_out",
submodel=model.control_volume.properties_out,
submodel_scalers=submodel_scalers,
method="variable_scaling_routine",
overwrite=overwrite,
Expand Down Expand Up @@ -152,16 +150,14 @@ def constraint_scaling_routine(
# Step 1: Call Scalers for state blocks
# Inlet properties
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_in",
submodel=model.control_volume.properties_in,
submodel_scalers=submodel_scalers,
method="constraint_scaling_routine",
overwrite=overwrite,
)
# Outlet properties
self.call_submodel_scaler_method(
model=model,
submodel="control_volume.properties_out",
submodel=model.control_volume.properties_out,
submodel_scalers=submodel_scalers,
method="constraint_scaling_routine",
overwrite=overwrite,
Expand Down
4 changes: 2 additions & 2 deletions idaes/models/unit_models/tests/test_gibbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,8 +636,8 @@ def model(self):
scaler.scale_model(
m.fs.unit,
submodel_scalers={
"control_volume.properties_in": PropertyScaler,
"control_volume.properties_out": PropertyScaler,
m.fs.unit.control_volume.properties_in: PropertyScaler,
m.fs.unit.control_volume.properties_out: PropertyScaler,
},
)

Expand Down
Loading