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

Activating IPOPT_V2 with presolver #1436

Merged
merged 24 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
11 changes: 1 addition & 10 deletions idaes/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,15 +328,13 @@ def _new_idaes_config_block():
pyomo.common.config.ConfigBlock(
implicit=False,
description="Default config for 'ipopt' solver",
doc="Default config for 'ipopt' solver",
),
)
cfg["ipopt_v2"].declare(
"options",
pyomo.common.config.ConfigBlock(
implicit=True,
description="Default solver options for 'ipopt'",
doc="Default solver options for 'ipopt' solver",
),
)

Expand All @@ -346,7 +344,6 @@ def _new_idaes_config_block():
domain=str,
default="gradient-based",
description="Ipopt NLP scaling method",
doc="Ipopt NLP scaling method",
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the difference between the doc and description fields, anyway?

Copy link
Member Author

Choose a reason for hiding this comment

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

Long (doc) and short (description) doc strings - which one shows up depends on exactly what you use to display the config block/value.

),
)

Expand All @@ -356,7 +353,6 @@ def _new_idaes_config_block():
domain=float,
default=1e-6,
description="Ipopt tol option",
doc="Ipopt tol option",
),
)

Expand All @@ -366,7 +362,6 @@ def _new_idaes_config_block():
domain=int,
default=200,
description="Ipopt max_iter option",
doc="Ipopt max_iter option",
),
)

Expand All @@ -376,7 +371,6 @@ def _new_idaes_config_block():
domain=str,
default="ma57",
description="Linear solver to be used by IPOPT",
doc="Linear solver to be used by IPOPT",
),
)

Expand All @@ -385,18 +379,16 @@ def _new_idaes_config_block():
pyomo.common.config.ConfigBlock(
implicit=True,
description="Default writer configuration for 'ipopt'",
doc="Default writer configuration for 'ipopt' solver",
),
)

# TODO: Remember to update BTInitializer to sue get_solver once scaling tools are deployed.
# TODO: Remember to update BTInitializer to use get_solver once scaling tools are deployed.
cfg["ipopt_v2"]["writer_config"].declare(
"scale_model",
pyomo.common.config.ConfigValue(
domain=Bool,
default=False, # TODO: Change to true once transition complete
description="Whether to apply model scaling in writer",
doc="Whether to apply model scaling in writer",
),
)

Expand All @@ -406,7 +398,6 @@ def _new_idaes_config_block():
domain=Bool,
default=True,
description="Whether to apply linear presolve in writer",
doc="Whether to apply linear presolve in writer",
),
)

Expand Down
4 changes: 4 additions & 0 deletions idaes/core/solvers/get_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,17 @@ def get_solver(
solver_obj = idaes.core.solvers.SolverWrapper(solver, register=False)()

if isinstance(solver_obj, LegacySolverWrapper):
Copy link
Contributor

Choose a reason for hiding this comment

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

It is unfortunate that we need to have this test here: the whole point of the Legacy interface is that you shouldn't have to change your code. Is there a reason why you can't just do:

if options is not None:
    for k, v in options.items():
        solver_obj.options[k] = v
if writer_config is not None:
    for k, v in writer_config.items():
        solver_obj.config.writer_config[k] = v

for both new and old solvers? If there writer_config is not None for an old solver, it should just generate an error when you try to set the value on config.writer_config...

Copy link
Member Author

Choose a reason for hiding this comment

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

I can definitely try (and this is why I was waiting for your review).

# New solver interface.
# LegacySolverWrapper is a wrapper for the new solver interface that makes it
# backward compatible.
if options is not None:
for k, v in options.items():
solver_obj.options[k] = v
if writer_config is not None:
for k, v in writer_config.items():
solver_obj.config.writer_config[k] = v
else:
# Old solver interface
if options is not None:
solver_obj.options.update(options)
if writer_config is not None:
Expand Down
4 changes: 2 additions & 2 deletions idaes/core/util/phase_equilibria.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def Txy_data(
"""
Function to generate T-x-y data. The function builds a state block and extracts
bubble and dew temperatures at P pressure for N number of compositions.
As N is increased increase the time of the calculation will increase and
As N is increased the time of the calculation will increase and
create a smoother looking plot.

Args:
Expand All @@ -113,7 +113,7 @@ def Txy_data(
pressure: Pressure at which the bubble and drew temperatures will be calculated
temperature: Temperature at which to initialize state block
num_points: Number of data point to be calculated
model: Model wit initialized Property package which contains data to calculate
model: Model with initialized property package which contains data to calculate
bubble and dew temperatures for component 1 and component 2
print_level: printing level from initialization
solver: solver to use (default=None, use IDAES default solver)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
)
from pyomo.common.config import ConfigBlock, ConfigDict, ConfigValue, In, Bool
from pyomo.util.calc_var_value import calculate_variable_from_constraint
from pyomo.contrib.incidence_analysis import solve_strongly_connected_components

Check warning on line 36 in idaes/models/properties/modular_properties/base/generic_property.py

View workflow job for this annotation

GitHub Actions / Pylint

W0611 (unused-import)

Unused solve_strongly_connected_components imported from pyomo.contrib.incidence_analysis

Check warning on line 36 in idaes/models/properties/modular_properties/base/generic_property.py

View workflow job for this annotation

GitHub Actions / Pylint

W0611 (unused-import)

Unused solve_strongly_connected_components imported from pyomo.contrib.incidence_analysis

# Import IDAES cores
from idaes.core import (
Expand Down Expand Up @@ -1214,9 +1214,6 @@
3. Solve for phase-equilibrium conditions
4. Initialize all remaining properties

The Pyomo solve_strongly_connected_components method is used at each
step to converge the problem.

Note that for systems without vapor-liquid equilibrium the generic
BlockTriangularizationInitializer is probably sufficient for initializing
the property package.
Expand Down Expand Up @@ -1376,13 +1373,8 @@
f"initialization at bubble, dew, and critical point step: "
f"{degrees_of_freedom(b)}."
)
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
solve_strongly_connected_components(
b,
solver=solver_obj,
solve_kwds={"tee": slc.tee},
calc_var_kwds=self.config.calculate_variable_options,
)
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
solve_indexed_blocks(solver_obj, model, tee=slc.tee)
init_log.info("Bubble, dew, and critical point initialization completed.")

# ---------------------------------------------------------------------
Expand Down Expand Up @@ -1503,23 +1495,18 @@
pp
].phase_equil_initialization(b, pp)

if number_activated_constraints(b) > 0:
dof = degrees_of_freedom(b)
if degrees_of_freedom(b) == 0:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
solve_strongly_connected_components(
b,
solver=solver_obj,
solve_kwds={"tee": slc.tee},
calc_var_kwds=self.config.calculate_variable_options,
)
elif dof > 0:
raise InitializationError(
f"{b.name} Unexpected degrees of freedom during "
f"initialization at phase equilibrium step: {dof}."
)
# Skip solve if DoF < 0 - this is probably due to a
# phase-component flow state with flash
if number_activated_constraints(model) > 0:
dof = degrees_of_freedom(model)
if dof == 0:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
solve_indexed_blocks(solver_obj, [model], tee=slc.tee)
elif dof > 0:
raise InitializationError(
f"{model.name} Unexpected degrees of freedom during "
f"initialization at phase equilibrium step: {dof}."
)
# Skip solve if DoF < 0 - this is probably due to a
# phase-component flow state with flash

init_log.info("Phase equilibrium initialization completed.")

Expand Down Expand Up @@ -1569,27 +1556,22 @@
lc = log(c)
v.set_value(value(lc))

if number_activated_constraints(b) > 0:
dof = degrees_of_freedom(b)
if degrees_of_freedom(b) == 0:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
solve_strongly_connected_components(
b,
solver=solver_obj,
solve_kwds={"tee": slc.tee},
calc_var_kwds=self.config.calculate_variable_options,
)
elif dof > 0:
raise InitializationError(
f"{b.name} Unexpected degrees of freedom during "
f"initialization at phase equilibrium step: {dof}."
)
# Skip solve if DoF < 0 - this is probably due to a
# phase-component flow state with flash
if number_activated_constraints(model) > 0:
dof = degrees_of_freedom(model)
if dof == 0:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
result = solve_indexed_blocks(solver_obj, model, tee=slc.tee)
elif dof > 0:
raise InitializationError(
f"{model.name} Unexpected degrees of freedom during "
f"initialization at phase equilibrium step: {dof}."
)
# Skip solve if DoF < 0 - this is probably due to a
# phase-component flow state with flash

init_log.info("Property initialization routine finished.")

return None
return result


class _GenericStateBlock(StateBlock):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ def model(self):
},
)

m.props = m.params.state_block_class(
m.props = m.params.build_state_block(
[1], defined_state=True, parameters=m.params
)

Expand Down
1 change: 0 additions & 1 deletion idaes/models/unit_models/mscontactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
)
from idaes.core.initialization import ModularInitializerBase
from idaes.core.initialization.initializer_base import StoreState
from idaes.core.solvers import get_solver
from idaes.core.util.model_serializer import to_json, from_json
import idaes.logger as idaeslog
from idaes.core.util.units_of_measurement import report_quantity
Expand Down
Loading