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

More Initializer Testing #1170

Merged
merged 34 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
f4328b3
Moving common mehtods to base class
andrewlee94 Apr 6, 2023
b96a873
Moving common tests to base class
andrewlee94 Apr 6, 2023
a1285fa
cleaning up
andrewlee94 Apr 6, 2023
ab50efa
Merging main
andrewlee94 Apr 11, 2023
50006d1
Testing rstoic and heater
andrewlee94 Apr 11, 2023
3523659
Adding Feed initializer
andrewlee94 Apr 11, 2023
1cca876
Changing BT solver to IPOPT
andrewlee94 Apr 11, 2023
917ced6
Removing skipif for AmplInterface
andrewlee94 Apr 11, 2023
27a3f88
Testing Gibbs reactor
andrewlee94 Apr 11, 2023
24a3465
Fixing pylint issues
andrewlee94 Apr 11, 2023
ca57421
HX0D Initializer
andrewlee94 Apr 11, 2023
ce838d0
Mixer Initializer
andrewlee94 Apr 12, 2023
e359744
Testing PFR
andrewlee94 Apr 12, 2023
1b510d4
Pressure changer with bug
andrewlee94 Apr 12, 2023
3c75a58
Fixing issue with external functions
andrewlee94 Apr 12, 2023
a7e682a
Switch to BT Initializer for properties
andrewlee94 Apr 13, 2023
9c5fb32
Product initializers
andrewlee94 Apr 13, 2023
66889e3
Working on Separator
andrewlee94 Apr 14, 2023
f857d8f
Testing Separator
andrewlee94 Apr 14, 2023
2e08bb3
Fixing bugs
andrewlee94 Apr 14, 2023
2f7a1a4
Merge branch 'main' into initializers_3
andrewlee94 Apr 17, 2023
7b8bf38
Fixing conflict
andrewlee94 Apr 17, 2023
c25f812
Fixing typo
andrewlee94 Apr 17, 2023
eb15156
Merge branch 'initializers_3' into initializers_4
andrewlee94 Apr 17, 2023
76c64c7
Fixing typo
andrewlee94 Apr 18, 2023
da30ccb
Merge branch 'initializers_3' into initializers_4
andrewlee94 Apr 18, 2023
4c54fc4
Fixing conflicts
andrewlee94 Apr 18, 2023
eba917e
Removing duplicate exception
andrewlee94 Apr 18, 2023
699cae2
Removing commented code
andrewlee94 Apr 18, 2023
5bff4f7
Fixing typo
andrewlee94 Apr 18, 2023
7822ad0
Fixing test failures
andrewlee94 Apr 18, 2023
6572482
Fixing issues with git merge
andrewlee94 Apr 18, 2023
ee90c90
Merge branch 'main' of https://github.com/IDAES/idaes-pse into initia…
andrewlee94 Apr 19, 2023
2a95be8
Removing unneeded exception
andrewlee94 Apr 19, 2023
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
16 changes: 8 additions & 8 deletions idaes/core/initialization/general_hierarchical.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,7 @@ def initialization_routine(
Returns:
Pyomo solver results object
"""
# Check to make sure model has something named "control_volume"
if not hasattr(model, "control_volume"):
raise TypeError(
f"Model {model.name} does not appear to be a standard form unit model. "
f"Please use an Initializer specific to the model being initialized."
)

# From here, the default initialization_routine is sufficient
# The default initialization_routine is sufficient
return super().initialization_routine(
model=model,
plugin_initializer_args=plugin_initializer_args,
Expand All @@ -94,6 +87,13 @@ def initialize_main_model(self, model: Block, copy_inlet_state: bool = False):
Pyomo solver results object from solve of main model

"""
# Check to make sure model has something named "control_volume"
if not hasattr(model, "control_volume"):
raise TypeError(
f"Model {model.name} does not appear to be a standard form unit model. "
f"Please use an Initializer specific to the model being initialized."
)

# Get logger
_log = self.get_logger(model)

Expand Down
13 changes: 6 additions & 7 deletions idaes/core/initialization/initializer_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def initialize(
initial_guesses: dict = None,
json_file: str = None,
output_level=None,
exclude_unused_vars: bool = False,
):
"""
Execute full initialization routine.
Expand All @@ -160,6 +161,7 @@ def initialize(
initial_guesses: dict of initial guesses to load.
json_file: file name of json file to load initial guesses from as str.
output_level: (optional) output level to use during initialization run (overrides global setting).
exclude_unused_vars: whether to ignore unused variables when doing post-initialization checks.

Note - can only provide one of initial_guesses or json_file.

Expand Down Expand Up @@ -196,7 +198,9 @@ def initialize(
self._local_logger_level = None

# 7. Check convergence
return self.postcheck(model, results_obj=results)
return self.postcheck(
model, results_obj=results, exclude_unused_vars=exclude_unused_vars
)

def get_current_state(self, model: Block):
"""
Expand Down Expand Up @@ -638,7 +642,7 @@ def initialization_routine(
self, model: Block, plugin_initializer_args: dict = None, **kwargs
):
"""
Common initialization routine for models with one control volume.
Common initialization routine for models with plugins.

Args:
model: Pyomo Block to be initialized
Expand All @@ -649,11 +653,6 @@ def initialization_routine(
Returns:
Pyomo solver results object
"""
if not hasattr(model, "control_volume"):
raise TypeError(
f"Model {model.name} does not appear to be a standard form unit model. "
f"Please use an Initializer specific to the model being initialized."
)
if plugin_initializer_args is None:
plugin_initializer_args = {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@
import pytest
import types

from pyomo.environ import ConcreteModel, Constraint, value, Var
from pyomo.environ import ConcreteModel, Constraint, units, value, Var

from idaes.core import FlowsheetBlock
from idaes.core.initialization.block_triangularization import (
BlockTriangularizationInitializer,
)
from idaes.core.initialization.initializer_base import InitializationStatus
from idaes.models.unit_models.pressure_changer import (
Turbine,
)

from idaes.models.properties import iapws95

__author__ = "Andrew Lee"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@pytest.mark.unit
def test_nonstandard_model():
m = ConcreteModel()
m.initialization_order = [m]

initializer = SingleControlVolumeUnitInitializer()

Expand Down Expand Up @@ -116,7 +117,6 @@ def test_init_props_1D():
m.control_volume.properties = Block()

initializer = SingleControlVolumeUnitInitializer()
log = initializer.get_logger(m)

def estimate_states(block, *args, **kwargs):
block._estimated = True
Expand Down Expand Up @@ -240,9 +240,6 @@ def test_initialize_control_volume_copy():
assert m.control_volume.reactions._initialized


# TODO: init props 1D


@pytest.mark.unit
def test_initialize_submodels_no_order():
m = ConcreteModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@

References:

1. "The properties of gases and liquids by Robert C. Reid"
2. "Perry's Chemical Engineers Handbook by Robert H. Perry".
3. H. Renon and J.M. Prausnitz, "Local compositions in thermodynamic excess functions for liquid mixtures.", AIChE Journal Vol. 14, No.1, 1968.
#. "The properties of gases and liquids by Robert C. Reid"
#. "Perry's Chemical Engineers Handbook by Robert H. Perry".
#. H. Renon and J.M. Prausnitz, "Local compositions in thermodynamic excess
functions for liquid mixtures.", AIChE Journal Vol. 14, No.1, 1968.

"""
# TODO: Missing docstrings
Expand All @@ -46,6 +47,7 @@

# Import Pyomo libraries
from pyomo.environ import (
Block,
check_optimal_termination,
Constraint,
log,
Expand All @@ -58,7 +60,7 @@
sqrt,
units as pyunits,
)
from pyomo.common.config import ConfigValue, In
from pyomo.common.config import ConfigDict, ConfigValue, In

# Import IDAES cores
from idaes.core import (
Expand All @@ -83,6 +85,7 @@
from idaes.core.solvers import get_solver
import idaes.core.util.scaling as iscale
import idaes.logger as idaeslog
from idaes.core.initialization import InitializerBase


# Some more information about this module
Expand Down Expand Up @@ -301,12 +304,186 @@ def define_metadata(cls, obj):
)


class ActivityCoeffInitializer(InitializerBase):
"""
Initializer for Activity Coefficient property packages.

This Initializer uses a hierarchical routine to initialize the
property package using 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.

"""

CONFIG = InitializerBase.CONFIG()
CONFIG.declare(
"solver",
ConfigValue(
default=None,
description="Solver to use for initialization",
),
)
CONFIG.declare(
"solver_options",
ConfigDict(
implicit=True,
description="Dict of options to pass to solver",
),
)
CONFIG.declare(
"calculate_variable_options",
ConfigDict(
implicit=True,
description="Dict of options to pass to 1x1 block solver",
doc="Dict of options to pass to calc_var_kwds argument in "
"solve_strongly_connected_components method. NOTE: models "
"involving ExternalFunctions must set "
"'diff_mode=differentiate.Modes.reverse_numeric'",
),
)

def __init__(self, **kwargs):
super().__init__(**kwargs)

self._solver = None

def initialization_routine(
self,
model: Block,
):
"""
Sequential initialization routine for cubic EoS properties.

Args:
model: model to be initialized

Returns:
None
"""
# Deactivate the constraints specific for outlet block i.e.
# when defined state is False
init_log = idaeslog.getInitLogger(
model.name, self.config.output_level, tag="properties"
)
solve_log = idaeslog.getSolveLogger(
model.name, self.config.output_level, tag="properties"
)

for k in model.values():
if (k.config.defined_state is False) and (
k.params.config.state_vars == "FTPz"
):
k.eq_mol_frac_out.deactivate()

# Create solver
solver = get_solver(self.config.solver, self.config.solver_options)

# ---------------------------------------------------------------------
# Initialization sequence: Deactivating certain constraints
# for 1st solve
for k in model.values():
for c in k.component_objects(Constraint):
if c.local_name in [
"eq_total",
"eq_comp",
"eq_phase_equilibrium",
"eq_enth_mol_phase",
"eq_entr_mol_phase",
"eq_Gij_coeff",
"eq_A",
"eq_B",
"eq_activity_coeff",
]:
c.deactivate()

# First solve for the active constraints that remain (p_sat, T_bubble,
# T_dew). Valid only for a 2 phase block. If single phase,
# no constraints are active.
# NOTE: "k" is the last value from the previous for loop
# only for the purpose of having a valid index. The assumption
# here is that for all values of "blk[k]", the attribute exists.
# TODO: This step can result in a non-square problem. This needs to be
# investigated
# TODO: Block Triangularization solver does not like this routine for some
# reason, maybe related to the above issue
if (
(k.config.has_phase_equilibrium)
or (k.config.parameters.config.valid_phase == ("Liq", "Vap"))
or (k.config.parameters.config.valid_phase == ("Vap", "Liq"))
):

with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
res = solve_indexed_blocks(solver, [model], tee=slc.tee)
else:
res = "skipped"
init_log.info(f"Initialization Step 1 {idaeslog.condition(res)}.")

# Continue initialization sequence and activate select constraints
for k in model.values():
for c in k.component_objects(Constraint):
if c.local_name in [
"eq_total",
"eq_comp",
"eq_phase_equilibrium",
]:
c.activate()
if k.config.parameters.config.activity_coeff_model != "Ideal":
# assume ideal and solve
k.activity_coeff_comp.fix(1)

# Second solve for the active constraints
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
res = solve_indexed_blocks(solver, [model], tee=slc.tee)
init_log.info(f"Initialization Step 2 {idaeslog.condition(res)}.")

# Activate activity coefficient specific constraints
for k in model.values():
if k.config.parameters.config.activity_coeff_model != "Ideal":
for c in k.component_objects(Constraint):
if c.local_name in ["eq_Gij_coeff", "eq_A", "eq_B"]:
c.activate()

with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
res = solve_indexed_blocks(solver, [model], tee=slc.tee)
init_log.info(f"Initialization Step 3 {idaeslog.condition(res)}.")

for k in model.values():
if k.config.parameters.config.activity_coeff_model != "Ideal":
k.eq_activity_coeff.activate()
k.activity_coeff_comp.unfix()

with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
res = solve_indexed_blocks(solver, [model], tee=slc.tee)
init_log.info(f"Initialization Step 4 {idaeslog.condition(res)}.")

for k in model.values():
for c in k.component_objects(Constraint):
if c.local_name in ["eq_enth_mol_phase", "eq_entr_mol_phase"]:
c.activate()

with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
res = solve_indexed_blocks(solver, [model], tee=slc.tee)
init_log.info(f"Initialization Step 5 {idaeslog.condition(res)}.")

return res


class _ActivityCoeffStateBlock(StateBlock):
"""
This Class contains methods which should be applied to Property Blocks as a
whole, rather than individual elements of indexed Property Blocks.
"""

# Set default initializer
default_initializer = ActivityCoeffInitializer

def fix_initialization_states(self):
"""
Fixes state variables for state blocks.
Expand Down
Loading