diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 0151406d..75fae0cf 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -1,5 +1,4 @@ name: Tests - on: push: branches: @@ -88,7 +87,7 @@ jobs: - win64 include: - os: linux - runner-image: ubuntu-20.04 + runner-image: ubuntu-latest - os: win64 runner-image: windows-2022 steps: @@ -109,10 +108,10 @@ jobs: run: | pwd ls idaes_examples - pytest -v idaes_examples --ignore=idaes_examples/notebooks/docs/surrogates/sco2/alamo/ + pytest -v idaes_examples --ignore=idaes_examples/notebooks/docs/surrogates/sco2/alamo/ - name: Upload pytest-xdist worker logs if: success() || failure() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: pytest_worker_logs + name: pytest-xdist-logs-${{ matrix.python-version }}-${{ runner.os }} path: "tests_*.log" diff --git a/idaes_examples/mod/hda/hda_ideal_VLE.py b/idaes_examples/mod/hda/hda_ideal_VLE.py index b6c3207e..2a7fe1ab 100644 --- a/idaes_examples/mod/hda/hda_ideal_VLE.py +++ b/idaes_examples/mod/hda/hda_ideal_VLE.py @@ -23,6 +23,7 @@ log, NonNegativeReals, Var, + value, Set, Param, sqrt, @@ -45,6 +46,7 @@ LiquidPhase, VaporPhase, ) +from idaes.core.util.model_statistics import degrees_of_freedom from idaes.core.util.constants import Constants as const from idaes.core.util.initialization import fix_state_vars, solve_indexed_blocks from idaes.core.initialization import InitializerBase @@ -548,10 +550,10 @@ def fix_initialization_states(blk): # Fix state variables fix_state_vars(blk) - # Also need to deactivate sum of mole fraction constraint - for k in blk.values(): - if not k.config.defined_state: - k.equilibrium_constraint.deactivate() + # # Also need to deactivate sum of mole fraction constraint + # for k in blk.values(): + # if not k.config.defined_state: + # k.equilibrium_constraint.deactivate() @declare_process_block_class("IdealStateBlock", block_class=_IdealStateBlock) @@ -1011,7 +1013,7 @@ def calculate_dew_point_pressure(self, clear_components=True): # as needed def _temperature_bubble(self): self.temperature_bubble = Param( - initialize=33.0, units=pyunits.K, doc="Bubble point temperature" + initialize=298.15, units=pyunits.K, doc="Bubble point temperature" ) def _temperature_dew(self): @@ -1039,7 +1041,7 @@ def rule_psat_dew(b, j): ) def rule_temp_dew(b): - return ( + ans = ( b.pressure * sum( b.mole_frac_comp[i] / b._p_sat_dewT[i] @@ -1048,6 +1050,7 @@ def rule_temp_dew(b): - 1 == 0 ) + return ans self.eq_temperature_dew = Constraint(rule=rule_temp_dew) except AttributeError: diff --git a/idaes_examples/mod/hda/hda_ideal_VLE_modular.py b/idaes_examples/mod/hda/hda_ideal_VLE_modular.py new file mode 100644 index 00000000..13ffff4a --- /dev/null +++ b/idaes_examples/mod/hda/hda_ideal_VLE_modular.py @@ -0,0 +1,320 @@ +################################################################################# +# The Institute for the Design of Advanced Energy Systems Integrated Platform +# Framework (IDAES IP) was produced under the DOE Institute for the +# Design of Advanced Energy Systems (IDAES). +# +# Copyright (c) 2018-2024 by the software owners: The Regents of the +# University of California, through Lawrence Berkeley National Laboratory, +# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon +# University, West Virginia University Research Corporation, et al. +# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md +# for full copyright and license information. +################################################################################# +""" +Benzene-Toluene phase equilibrium package using ideal liquid and vapor. + +Example property package using the Generic Property Package Framework. +This exmample shows how to set up a property package to do benzene-toluene +phase equilibrium in the generic framework using ideal liquid and vapor +assumptions along with methods drawn from the pre-built IDAES property +libraries. +""" +import copy + +# Import Pyomo units +from pyomo.environ import units as pyunits, Var, value + +# Import IDAES cores +from idaes.core import LiquidPhase, VaporPhase, Component, PhaseType +import idaes.logger as idaeslog + +from idaes.core.util.math import smooth_max +from idaes.core.util.constants import Constants + +from idaes.models.properties.modular_properties.state_definitions.FpTPxpc import FpTPxpc +from idaes.models.properties.modular_properties.eos.ideal import Ideal +from idaes.models.properties.modular_properties.phase_equil import SmoothVLE +from idaes.models.properties.modular_properties.phase_equil.bubble_dew import ( + IdealBubbleDew, +) +from idaes.core.util.misc import set_param_from_config +from idaes.models.properties.modular_properties.phase_equil.forms import fugacity +from idaes.models.properties.modular_properties.pure import Perrys +from idaes.models.properties.modular_properties.pure import RPP5 + +# Set up logger +_log = idaeslog.getLogger(__name__) +R = value(Constants.gas_constant) +# --------------------------------------------------------------------- +# Configuration dictionary for an ideal Benzene-Toluene system + +# Data Sources: +# [1] The Properties of Gases and Liquids (1987) +# 4th edition, Chemical Engineering Series - Robert C. Reid +# [2] Perry's Chemical Engineers' Handbook 7th Ed. +# [3] Engineering Toolbox, https://www.engineeringtoolbox.com +# Retrieved 1st December, 2019 +# [4] Properties of Gases and Liquids (2000) 5th edition +# Poling, B. E. and Prausnitz, J. M. and O'Connell, J. P. +# McGraw Hill LLC +# Might be the second printing---copyright was from 2001 + +# Legacy values from [1] +cp_ig_data = { + ("benzene", 0): -3.392e1 / R, + ("benzene", 1): 4.739e-1 / R, + ("benzene", 2): -3.017e-4 / R, + ("benzene", 3): 7.130e-8 / R, + ("benzene", 4): 0, + ("toluene", 0): -2.435e1 / R, + ("toluene", 1): 5.125e-1 / R, + ("toluene", 2): -2.765e-4 / R, + ("toluene", 3): 4.911e-8 / R, + ("toluene", 4): 0, + ("hydrogen", 0): 2.714e1 / R, + ("hydrogen", 1): 9.274e-3 / R, + ("hydrogen", 2): -1.381e-5 / R, + ("hydrogen", 3): 7.645e-9 / R, + ("hydrogen", 4): 0, + ("methane", 0): 1.925e1 / R, + ("methane", 1): 5.213e-2 / R, + ("methane", 2): 1.197e-5 / R, + ("methane", 3): -1.132e-8 / R, + ("methane", 4): 0, +} + + +class PerrysSafe(object): + class dens_mol_liq_comp: + @staticmethod + def build_parameters(cobj): + cobj.dens_mol_liq_comp_coeff_1 = Var( + doc="Parameter 1 for liquid phase molar density", + units=pyunits.kmol * pyunits.m**-3, + ) + set_param_from_config(cobj, param="dens_mol_liq_comp_coeff", index="1") + + cobj.dens_mol_liq_comp_coeff_2 = Var( + doc="Parameter 2 for liquid phase molar density", + units=pyunits.dimensionless, + ) + set_param_from_config(cobj, param="dens_mol_liq_comp_coeff", index="2") + + cobj.dens_mol_liq_comp_coeff_3 = Var( + doc="Parameter 3 for liquid phase molar density", units=pyunits.K + ) + set_param_from_config(cobj, param="dens_mol_liq_comp_coeff", index="3") + + cobj.dens_mol_liq_comp_coeff_4 = Var( + doc="Parameter 4 for liquid phase molar density", + units=pyunits.dimensionless, + ) + set_param_from_config(cobj, param="dens_mol_liq_comp_coeff", index="4") + + @staticmethod + def return_expression(b, cobj, T): + # pg. 2-98 + T = pyunits.convert(T, to_units=pyunits.K) + + rho = cobj.dens_mol_liq_comp_coeff_1 / cobj.dens_mol_liq_comp_coeff_2 ** ( + 1 + + smooth_max(1 - T / cobj.dens_mol_liq_comp_coeff_3, 0) + ** cobj.dens_mol_liq_comp_coeff_4 + ) + + units = b.params.get_metadata().derived_units + + return pyunits.convert(rho, units.DENSITY_MOLE) + + +thermo_config = { + # Specifying components + "components": { + "benzene": { + "type": Component, + "elemental_composition": {"C": 6, "H": 6}, + "dens_mol_liq_comp": PerrysSafe, + "enth_mol_liq_comp": Perrys, + "enth_mol_ig_comp": RPP5, + "pressure_sat_comp": RPP5, + "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, + "parameter_data": { + "mw": (78.1136e-3, pyunits.kg / pyunits.mol), # [1] + "pressure_crit": (48.9e5, pyunits.Pa), # [1] + "temperature_crit": (562.2, pyunits.K), # [1] + "dens_mol_liq_comp_coeff": { + "eqn_type": 1, + "1": (1.0162, pyunits.kmol * pyunits.m**-3), # [2] pg. 2-98 + "2": (0.2655, None), + "3": (562.16, pyunits.K), + "4": (0.28212, None), + }, + "cp_mol_ig_comp_coeff": { + f"a{k}": (cp_ig_data["benzene", k], pyunits.K**-k) for k in range(5) + }, + "cp_mol_liq_comp_coeff": { + "1": (1.29e2 * 1e3, pyunits.J / pyunits.kmol / pyunits.K), # [2] + "2": (-1.7e-1 * 1e3, pyunits.J / pyunits.kmol / pyunits.K**2), + "3": (6.48e-4 * 1e3, pyunits.J / pyunits.kmol / pyunits.K**3), + "4": (0, pyunits.J / pyunits.kmol / pyunits.K**4), + "5": (0, pyunits.J / pyunits.kmol / pyunits.K**5), + }, + "enth_mol_form_liq_comp_ref": (49.0e3, pyunits.J / pyunits.mol), # [3] + "enth_mol_form_vap_comp_ref": (82.9e3, pyunits.J / pyunits.mol), # [3] + "pressure_sat_comp_coeff": { + "A": (4.202, pyunits.dimensionless), # [1] + "B": (1322, pyunits.K), + "C": (-38.56 + 273.15, pyunits.K), + }, + }, + }, + "toluene": { + "type": Component, + "elemental_composition": {"C": 7, "H": 8}, + "dens_mol_liq_comp": PerrysSafe, + "enth_mol_liq_comp": Perrys, + "enth_mol_ig_comp": RPP5, + "pressure_sat_comp": RPP5, + "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, + "parameter_data": { + "mw": (92.1405e-3, pyunits.kg / pyunits.mol), # [1] + "pressure_crit": (41e5, pyunits.Pa), # [1] + "temperature_crit": (591.8, pyunits.K), # [1] + "dens_mol_liq_comp_coeff": { + "eqn_type": 1, + "1": (0.8488, pyunits.kmol * pyunits.m**-3), # [2] pg. 2-98 + "2": (0.26655, None), + "3": (591.8, pyunits.K), + "4": (0.2878, None), + }, + "cp_mol_ig_comp_coeff": { + f"a{k}": (cp_ig_data["toluene", k], pyunits.K**-k) for k in range(5) + }, + "cp_mol_liq_comp_coeff": { + "1": (1.40e2 * 1e3, pyunits.J / pyunits.kmol / pyunits.K), # [2] + "2": (-1.52e-1 * 1e3, pyunits.J / pyunits.kmol / pyunits.K**2), + "3": (6.95e-4 * 1e3, pyunits.J / pyunits.kmol / pyunits.K**3), + "4": (0, pyunits.J / pyunits.kmol / pyunits.K**4), + "5": (0, pyunits.J / pyunits.kmol / pyunits.K**5), + }, + "enth_mol_form_liq_comp_ref": (12.0e3, pyunits.J / pyunits.mol), # [3] + "enth_mol_form_vap_comp_ref": (50.1e3, pyunits.J / pyunits.mol), # [3] + "pressure_sat_comp_coeff": { + "A": (4.216, pyunits.dimensionless), # [1] + "B": (1435, pyunits.K), + "C": (-43.33 + 273.15, pyunits.K), + }, + }, + }, + "hydrogen": { + "type": Component, + "valid_phase_types": [PhaseType.vaporPhase], + "elemental_composition": {"H": 2}, + "enth_mol_ig_comp": RPP5, + "pressure_sat_comp": RPP5, + "parameter_data": { + "mw": (2.016e-3, pyunits.kg / pyunits.mol), # [1] + "pressure_crit": (12.9e5, pyunits.Pa), # [1] + "temperature_crit": (33.0, pyunits.K), # [1] + # "dens_mol_liq_comp_coeff": { + # "eqn_type": 1, + # "1": (5.414, pyunits.kmol * pyunits.m ** -3), # [2] pg. 2-98 + # "2": (0.34893, None), + # "3": (33.19, pyunits.K), + # "4": (0.2706, None), + # }, + "cp_mol_ig_comp_coeff": { + f"a{k}": (cp_ig_data["hydrogen", k], pyunits.K**-k) + for k in range(5) + }, + # "cp_mol_liq_comp_coeff": { + # "1": (0, pyunits.J / pyunits.kmol / pyunits.K), # [2] + # "2": (0, pyunits.J / pyunits.kmol / pyunits.K ** 2), + # "3": (0, pyunits.J / pyunits.kmol / pyunits.K ** 3), + # "4": (0, pyunits.J / pyunits.kmol / pyunits.K ** 4), + # "5": (0, pyunits.J / pyunits.kmol / pyunits.K ** 5), + # }, + # "enth_mol_form_liq_comp_ref": (0.0, pyunits.J / pyunits.mol), # [3] + "enth_mol_form_vap_comp_ref": (0.0, pyunits.J / pyunits.mol), # [3] + "pressure_sat_comp_coeff": { + "A": (3.543, pyunits.dimensionless), # [1] + "B": (99.40, pyunits.K), + "C": (7.726 + 273.15, pyunits.K), + }, + }, + }, + "methane": { + "type": Component, + "valid_phase_types": [PhaseType.vaporPhase], + "elemental_composition": {"C": 1, "H": 4}, + "enth_mol_ig_comp": RPP5, + "pressure_sat_comp": RPP5, + "parameter_data": { + "mw": (16.043e-3, pyunits.kg / pyunits.mol), # [1] + "pressure_crit": (4.599e6, pyunits.Pa), # [1] + "temperature_crit": (190.564, pyunits.K), # [1] + # "dens_mol_liq_comp_coeff": { + # "eqn_type": 1, + # "1": (2.9214, pyunits.kmol * pyunits.m ** -3), # [2] pg. 2-98 + # "2": (0.28976, None), + # "3": (190.56, pyunits.K), + # "4": (0.28881, None), + # }, + "cp_mol_ig_comp_coeff": { + f"a{k}": (cp_ig_data["methane", k], pyunits.K**-k) for k in range(5) + }, + # "cp_mol_liq_comp_coeff": { + # "1": (0, pyunits.J / pyunits.kmol / pyunits.K), # [2] + # "2": (0, pyunits.J / pyunits.kmol / pyunits.K ** 2), + # "3": (0, pyunits.J / pyunits.kmol / pyunits.K ** 3), + # "4": (0, pyunits.J / pyunits.kmol / pyunits.K ** 4), + # "5": (0, pyunits.J / pyunits.kmol / pyunits.K ** 5), + # }, + # "enth_mol_form_liq_comp_ref": (-74.52e3, pyunits.J / pyunits.mol), # [3] + "enth_mol_form_vap_comp_ref": ( + -74.52e3, + pyunits.J / pyunits.mol, + ), # [3] + "pressure_sat_comp_coeff": { + "A": (3.990, pyunits.dimensionless), # [1] + "B": (443.0, pyunits.K), + "C": (-0.49 + 273.15, pyunits.K), + }, + }, + }, + }, + # Specifying phases + "phases": { + "Liq": {"type": LiquidPhase, "equation_of_state": Ideal}, + "Vap": {"type": VaporPhase, "equation_of_state": Ideal}, + }, + # + # # Set base units of measurement + "base_units": { + "time": pyunits.s, + "length": pyunits.m, + "mass": pyunits.kg, + "amount": pyunits.mol, + "temperature": pyunits.K, + }, + # # Specifying state definition + "state_definition": FpTPxpc, + "state_bounds": { + "flow_mol_phase": (1e-12, 0.5, 100, pyunits.mol / pyunits.s), + "temperature": (273.15, 298.15, 1500, pyunits.K), + "pressure": (100000, 101325, 1000000, pyunits.Pa), + }, + "pressure_ref": (101325, pyunits.Pa), + "temperature_ref": (298.15, pyunits.K), + # Defining phase equilibria + "phases_in_equilibrium": [("Vap", "Liq")], + "phase_equilibrium_state": {("Vap", "Liq"): SmoothVLE}, + "bubble_dew_method": IdealBubbleDew, # LogBubbleDew, + "include_enthalpy_of_formation": True, +} + +thermo_config_vapor = copy.deepcopy(thermo_config) +thermo_config_vapor["phases"].pop("Liq") +thermo_config_vapor.pop("phases_in_equilibrium") +thermo_config_vapor.pop("phase_equilibrium_state") +thermo_config_vapor.pop("bubble_dew_method") diff --git a/idaes_examples/mod/hda/hda_reaction_modular.py b/idaes_examples/mod/hda/hda_reaction_modular.py new file mode 100644 index 00000000..a662ad9c --- /dev/null +++ b/idaes_examples/mod/hda/hda_reaction_modular.py @@ -0,0 +1,95 @@ +################################################################################# +# The Institute for the Design of Advanced Energy Systems Integrated Platform +# Framework (IDAES IP) was produced under the DOE Institute for the +# Design of Advanced Energy Systems (IDAES). +# +# Copyright (c) 2018-2024 by the software owners: The Regents of the +# University of California, through Lawrence Berkeley National Laboratory, +# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon +# University, West Virginia University Research Corporation, et al. +# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md +# for full copyright and license information. +################################################################################# +""" +Benzene-Toluene phase equilibrium package using ideal liquid and vapor. + +Example property package using the Generic Property Package Framework. +This exmample shows how to set up a property package to do benzene-toluene +phase equilibrium in the generic framework using ideal liquid and vapor +assumptions along with methods drawn from the pre-built IDAES property +libraries. +""" +# Import Pyomo units +from pyomo.environ import units as pyunits + +# Import IDAES cores +from idaes.core import LiquidPhase, VaporPhase, Component +import idaes.logger as idaeslog + +from idaes.models.properties.modular_properties.state_definitions import FTPx +from idaes.models.properties.modular_properties.eos.ideal import Ideal +from idaes.models.properties.modular_properties.phase_equil import SmoothVLE +from idaes.models.properties.modular_properties.phase_equil.bubble_dew import ( + IdealBubbleDew, +) +from idaes.models.properties.modular_properties.phase_equil.forms import fugacity +from idaes.models.properties.modular_properties.pure import Perrys +from idaes.models.properties.modular_properties.pure import RPP5 +from idaes.models.properties.modular_properties.reactions.rate_forms import ( + power_law_rate, +) +from idaes.models.properties.modular_properties.reactions.dh_rxn import constant_dh_rxn +from idaes.models.properties.modular_properties.reactions.rate_constant import arrhenius +from idaes.models.properties.modular_properties.base.utility import ConcentrationForm + +# Set up logger +_log = idaeslog.getLogger(__name__) + +# --------------------------------------------------------------------- +# Configuration dictionary for an ideal Benzene-Toluene system + +# Data Sources: +# [1] The Properties of Gases and Liquids (1987) +# 4th edition, Chemical Engineering Series - Robert C. Reid +# [2] Perry's Chemical Engineers' Handbook 7th Ed. +# [3] Engineering Toolbox, https://www.engineeringtoolbox.com +# Retrieved 1st December, 2019 + +reaction_config = { + "rate_reactions": { + "hydrodealkylation": { + "stoichiometry": { + ("Vap", "benzene"): 1, + ("Vap", "toluene"): -1, + ("Vap", "hydrogen"): -1, + ("Vap", "methane"): 1, + }, + "heat_of_reaction": constant_dh_rxn, + "rate_constant": arrhenius, + "rate_form": power_law_rate, + "concentration_form": ConcentrationForm.partialPressure, + "parameter_data": { + "dh_rxn_ref": (-1.08e5, pyunits.J / pyunits.mol), + "arrhenius_const": ( + 6.3e10, + pyunits.mol * pyunits.m**-3 * pyunits.s**-1 * pyunits.Pa**-1.5, + ), + "energy_activation": (217.6e3, pyunits.J / pyunits.mol), + "reaction_order": { + ("Vap", "benzene"): 0, + ("Vap", "toluene"): 1.0, + ("Vap", "hydrogen"): 0.5, + ("Vap", "methane"): 0, + }, + }, + } + }, + # Set base units of measurement + "base_units": { + "time": pyunits.s, + "length": pyunits.m, + "mass": pyunits.kg, + "amount": pyunits.mol, + "temperature": pyunits.K, + }, +} diff --git a/idaes_examples/notebooks/docs/tut/core/HDA_flowsheet.png b/idaes_examples/notebooks/docs/tut/core/HDA_flowsheet.png index 837bafb5..e3a20f5f 100644 Binary files a/idaes_examples/notebooks/docs/tut/core/HDA_flowsheet.png and b/idaes_examples/notebooks/docs/tut/core/HDA_flowsheet.png differ diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit.ipynb index 6dc88109..98bea68f 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -23,41 +25,50 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "# Flash Unit Model\n", + "# Flash Unit Model Tutorial\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "## Key links to documentation\n", "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", "\n", "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", "\n", "
\n", "Inline Exercise:\n", @@ -66,23 +77,32 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", "from idaes.core import FlowsheetBlock\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -91,20 +111,29 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 3 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", + "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block. Lets use the `m.pprint()` to investigate the current contents of the model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -113,41 +142,64 @@ ] }, { - "cell_type": "code", - "execution_count": 3, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.531374Z", + "start_time": "2025-06-06T16:45:49.527521Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: call pprint on the model", "outputs": [], - "source": [ - "# Todo: call pprint on the model" - ] + "execution_count": 4 }, { - "cell_type": "code", - "execution_count": 4, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.577500Z", + "start_time": "2025-06-06T16:45:49.572256Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: call pprint on the model\n", "m.pprint()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Block Declarations\n", + " fs : Size=1, Index=None, Active=True\n", + " 1 Set Declarations\n", + " _time : Size=1, Index=None, Ordered=Insertion\n", + " Key : Dimen : Domain : Size : Members\n", + " None : 1 : Any : 1 : {0.0,}\n", + "\n", + " 1 Declarations: _time\n", + "\n", + "1 Declarations: fs\n" + ] + } + ], + "execution_count": 5 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Define Properties\n", + "### 2.1 Define Properties\n", "\n", "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", "\n", "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", "\n", @@ -158,38 +210,48 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", " BTXParameterBlock,\n", ")" - ] + ], + "outputs": [], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "m.fs.properties = BTXParameterBlock(\n", " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", ")" - ] + ], + "outputs": [], + "execution_count": 7 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Adding Flash Unit\n", + "### 2.2 Adding Flash Unit\n", "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", "\n", "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", "\n", "Some of the IDAES pre-written unit models:\n", "* Mixer / Splitter\n", @@ -200,7 +262,7 @@ "* Pressure changing equipment (compressors, expanders, pumps)\n", "* Feed and Product (source / sink) components\n", "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", "\n", "
\n", "Inline Exercise:\n", @@ -209,40 +271,183 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "source": "from idaes.models.unit_models import Flash", "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] + "execution_count": 8 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, "cell_type": "code", - "execution_count": 8, + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", + "outputs": [], + "execution_count": 9 + }, + { "metadata": {}, + "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.783706Z", + "start_time": "2025-06-06T16:45:49.781688Z" + }, + "tags": [ + "noauto" + ] + }, + "cell_type": "code", + "source": "m.pprint()", "outputs": [], + "execution_count": 10 + }, + { + "metadata": {}, + "cell_type": "markdown", "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" ] }, { + "metadata": {}, "cell_type": "markdown", + "source": [ + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", + "\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", + "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } + }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], + "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, "cell_type": "markdown", + "source": "" + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "## Set Operating Conditions\n", + "## 4 Set Operating Conditions\n", "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", "\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.1 Degrees of Freedom\n", + "\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", + "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", @@ -250,41 +455,71 @@ ] }, { - "cell_type": "code", - "execution_count": 9, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.224457Z", + "start_time": "2025-06-06T16:45:50.221905Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function" - ] + ], + "outputs": [], + "execution_count": 15 }, { - "cell_type": "code", - "execution_count": 10, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.240605Z", + "start_time": "2025-06-06T16:45:50.237594Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function\n", "help(degrees_of_freedom)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", + "\n", + "degrees_of_freedom(block)\n", + " Method to return the degrees of freedom of a model.\n", + "\n", + " Args:\n", + " block : model to be studied\n", + "\n", + " Returns:\n", + " Number of degrees of freedom in block.\n", + "\n" + ] + } + ], + "execution_count": 16 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -293,50 +528,70 @@ ] }, { - "cell_type": "code", - "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.271361Z", + "start_time": "2025-06-06T16:45:50.268763Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: print the degrees of freedom for your model", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 17 }, { - "cell_type": "code", - "execution_count": 12, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.297399Z", + "start_time": "2025-06-06T16:45:50.291352Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 7\n" + ] + } + ], + "execution_count": 18 }, { - "cell_type": "code", - "execution_count": 13, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.334804Z", + "start_time": "2025-06-06T16:45:50.327991Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 7" - ] + ], + "outputs": [], + "execution_count": 19 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", "\n", "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", @@ -353,7 +608,7 @@ "\n", "
\n", "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", "
\n", "\n", "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", @@ -373,7 +628,17 @@ "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", "* The heat duty on the flash set to 0 (`heat_duty`)\n", "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Write the code below to specify the inlet conditions and unit specifications described above\n", @@ -381,30 +646,36 @@ ] }, { - "cell_type": "code", - "execution_count": 14, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.360852Z", + "start_time": "2025-06-06T16:45:50.357341Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "\n", "\n", "# Todo: Add 2 flash unit specifications given above" - ] + ], + "outputs": [], + "execution_count": 20 }, { - "cell_type": "code", - "execution_count": 15, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.396800Z", + "start_time": "2025-06-06T16:45:50.392314Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "m.fs.flash.inlet.flow_mol.fix(1)\n", @@ -416,11 +687,25 @@ "# Todo: Add 2 flash unit specifications given above\n", "m.fs.flash.heat_duty.fix(0)\n", "m.fs.flash.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" ] }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -429,93 +714,161 @@ ] }, { - "cell_type": "code", - "execution_count": 16, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 22, + "source": "# Todo: print the degrees of freedom for your model" }, { - "cell_type": "code", - "execution_count": 17, "metadata": { "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 0\n" + ] + } + ], + "execution_count": 23, "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" ] }, { - "cell_type": "code", - "execution_count": 18, "metadata": { "tags": [ "testing" ] }, + "cell_type": "code", "outputs": [], + "execution_count": 24, "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Initializing the Model\n", + "## 5 Initializing the Model\n", "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", "\n", + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", + "Define the initializer instance, and initialize the flash unit model\n", "
" ] }, { - "cell_type": "code", - "execution_count": 19, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.499945Z", + "start_time": "2025-06-06T16:45:50.497439Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: initialize the flash unit", "outputs": [], - "source": [ - "# Todo: initialize the flash unit" - ] + "execution_count": 25 }, { - "cell_type": "code", - "execution_count": 20, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:51:40.247234Z", + "start_time": "2025-06-06T16:51:39.730044Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: initialize the flash unit\n", - "m.fs.flash.initialize(outlvl=idaeslog.INFO)" - ] + "FlashInitializer = m.fs.flash.default_initializer()\n", + "FlashInitializer.initialize(m.fs.flash)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 33 }, { + "metadata": {}, "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", + "## 6 Solving the Model\n", "\n", + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", @@ -523,58 +876,140 @@ ] }, { - "cell_type": "code", - "execution_count": 21, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.219172Z", + "start_time": "2025-06-06T17:04:32.216161Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "\n", "# Todo: solve the model" - ] + ], + "outputs": [], + "execution_count": 36 }, { - "cell_type": "code", - "execution_count": 22, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.439966Z", + "start_time": "2025-06-06T17:04:32.396984Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "solver = SolverFactory(\"ipopt\")\n", "\n", "# Todo: solve the model\n", "status = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 135\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 41\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.22e-05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e-11 1.00e-02 -1.0 6.22e-05 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 1\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 37 }, { - "cell_type": "code", - "execution_count": 23, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.975773Z", + "start_time": "2025-06-06T17:04:32.972754Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ - "# Check for optimal solution\n", + "# Check for an optimal solution\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert status.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 38 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Viewing the Results\n", + "## 7 Viewing the Results\n", "\n", "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", "```python\n", @@ -594,10 +1029,13 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], "source": [ "# Print the pressure of the flash vapor outlet\n", "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", @@ -607,38 +1045,95 @@ "# Call display on vap_outlet and liq_outlet of the flash\n", "m.fs.flash.vap_outlet.display()\n", "m.fs.flash.liq_outlet.display()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", "\n", "
\n", "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash.report()" - ] + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 }, { - "cell_type": "code", - "execution_count": 26, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:39.229802Z", + "start_time": "2025-06-06T17:04:39.132903Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check optimal solution values\n", "import pytest\n", @@ -662,13 +1157,15 @@ ")\n", "assert value(m.fs.flash.vap_outlet.temperature[0]) == pytest.approx(368, abs=1e-3)\n", "assert value(m.fs.flash.vap_outlet.pressure[0]) == pytest.approx(101325, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 41 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Studying Purity as a Function of Heat Duty\n", + "## Exercise: Studying Purity as a Function of Heat Duty\n", "\n", "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", "\n", @@ -680,22 +1177,35 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "source": "import matplotlib.pyplot as plt", "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] + "execution_count": 42 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Exercise specifications:\n", "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", @@ -703,14 +1213,12 @@ ] }, { - "cell_type": "code", - "execution_count": 29, "metadata": { "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -723,22 +1231,22 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "UnitModelInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "\n", " # fix the heat duty\n", " m.fs.flash.heat_duty.fix(duty)\n", - " \n", + "\n", " # append the value of the duty to the Q list\n", " Q.append(duty)\n", - " \n", + "\n", " # print the current simulation\n", " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", "\n", " # Solve the model\n", " status = solver.solve(m)\n", - " \n", + "\n", " # append the value for vapor fraction if the solve was successful\n", " if solve_successful(status):\n", " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", @@ -746,7 +1254,7 @@ " else:\n", " V.append(0.0)\n", " print('... solve failed.')\n", - " \n", + "\n", "# Create and show the figure\n", "plt.figure(\"Vapor Fraction\")\n", "plt.plot(Q, V)\n", @@ -754,18 +1262,21 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [], + "execution_count": null }, { - "cell_type": "code", - "execution_count": 30, "metadata": { - "scrolled": true, + "ExecuteTime": { + "end_time": "2025-06-06T17:04:48.800601Z", + "start_time": "2025-06-06T17:04:46.438264Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -778,7 +1289,7 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "FlashInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "for duty in np.linspace(-17000, 25000, 50):\n", @@ -809,11 +1320,244 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 43 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -822,27 +1566,27 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor", "outputs": [], - "source": [ - "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor" - ] + "execution_count": null }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:02.101331Z", + "start_time": "2025-06-06T17:05:00.157447Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", "Q = []\n", @@ -875,18 +1619,247 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 44 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", "\n", "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", "\n", "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", @@ -894,14 +1867,16 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.363302Z", + "start_time": "2025-06-06T17:05:04.960601Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -917,17 +1892,118 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 136\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.07e-08 1.01e-04 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e+00 2.42e-01 -1.0 4.86e+02 - 9.90e-01 1.00e+00f 1\n", + " 2 0.0000000e+00 5.55e+01 5.60e-03 -1.0 3.00e+03 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 1.91e+00 4.24e-05 -1.0 5.68e+02 - 1.00e+00 1.00e+00h 1\n", + " 4 0.0000000e+00 1.53e-05 1.90e-06 -2.5 1.35e+00 - 1.00e+00 1.00e+00h 1\n", + " 5 0.0000000e+00 4.66e-10 1.50e-09 -3.8 8.72e-03 - 1.00e+00 1.00e+00h 1\n", + " 6 0.0000000e+00 2.18e-11 1.84e-11 -5.7 1.92e-03 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 1.46e-11 2.51e-14 -8.6 2.10e-04 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 7\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 2.5059035640133008e-14 2.5059035640133008e-14\n", + "Constraint violation....: 4.8801876740451558e-13 1.4551915228366852e-11\n", + "Complementarity.........: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "Overall NLP error.......: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 9\n", + "Number of objective gradient evaluations = 8\n", + "Number of equality constraint evaluations = 9\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 8\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 7\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 4059.3 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.51773 0.48227 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60690 0.38524 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.39310 0.61476 \n", + " temperature kelvin 368.00 368.85 368.85 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 45 }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.768445Z", + "start_time": "2025-06-06T17:05:05.378930Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -946,17 +2022,110 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 137\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 42\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", + " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 6.96e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 5083.6 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.54833 0.45167 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", + " temperature kelvin 368.00 369.07 369.07 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 46 }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check for solver status\n", "assert status.solver.termination_condition == TerminationCondition.optimal\n", @@ -981,7 +2150,9 @@ ")\n", "assert value(m.fs.flash.vap_outlet.temperature[0]) == pytest.approx(369.07, abs=1e-2)\n", "assert value(m.fs.flash.vap_outlet.pressure[0]) == pytest.approx(101325, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": null } ], "metadata": { diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit_doc.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit_doc.ipynb index 9432ccbe..bb186921 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit_doc.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit_doc.ipynb @@ -1,1912 +1,1591 @@ { - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "header", - "hide-cell" - ] - }, - "outputs": [], - "source": [ - "###############################################################################\n", - "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", - "# Design of Advanced Energy Systems (IDAES).\n", - "#\n", - "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", - "# University of California, through Lawrence Berkeley National Laboratory,\n", - "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", - "# University, West Virginia University Research Corporation, et al.\n", - "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", - "# for full copyright and license information.\n", - "###############################################################################" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Flash Unit Model\n", - "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", - "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", - "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", - "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", - "\n", - "## Key links to documentation\n", - "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", - "\n", - "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", - "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the cell below to perform the imports. Let a workshop organizer know if you see any errors.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", - "from idaes.core import FlowsheetBlock\n", - "\n", - "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the cell below to create the objects\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "m = ConcreteModel()\n", - "m.fs = FlowsheetBlock(dynamic=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Use the pprint method on the model, i.e. m.pprint(), to see what is currently contained in the model.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 Block Declarations\n", - " fs : Size=1, Index=None, Active=True\n", - " 1 Set Declarations\n", - " _time : Size=1, Index=None, Ordered=Insertion\n", - " Key : Dimen : Domain : Size : Members\n", - " None : 1 : Any : 1 : {0.0,}\n", - "\n", - " 1 Declarations: _time\n", - "\n", - "1 Declarations: fs\n" - ] - } - ], - "source": [ - "# Todo: call pprint on the model\n", - "m.pprint()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Define Properties\n", - "\n", - "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", - "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", - "\n", - "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the following two cells to import and create the properties block.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", - " BTXParameterBlock,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.properties = BTXParameterBlock(\n", - " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Adding Flash Unit\n", - "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", - "\n", - "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", - "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", - "\n", - "Some of the IDAES pre-written unit models:\n", - "* Mixer / Splitter\n", - "* Heater / Cooler\n", - "* Heat Exchangers (simple and 1D discretized)\n", - "* Flash\n", - "* Reactors (kinetic, equilibrium, gibbs, stoichiometric conversion)\n", - "* Pressure changing equipment (compressors, expanders, pumps)\n", - "* Feed and Product (source / sink) components\n", - "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the following two cells to import the Flash and create an instance of the unit model, attaching it to the flowsheet object.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Set Operating Conditions\n", - "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", - "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", - "\n", - "degrees_of_freedom(block)\n", - " Method to return the degrees of freedom of a model.\n", - " \n", - " Args:\n", - " block : model to be studied\n", - " \n", - " Returns:\n", - " Number of degrees of freedom in block.\n", - "\n" - ] - } - ], - "source": [ - "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", - "\n", - "# Todo: Call the python help on the degrees_of_freedom function\n", - "help(degrees_of_freedom)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Now print the degrees of freedom for your model. The result should be 7.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Degrees of Freedom = 7\n" - ] - } - ], - "source": [ - "# Todo: print the degrees of freedom for your model\n", - "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", - "\n", - "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", - "\n", - "As an example, to fix the molar flow of the inlet to be 1.0, you can use the following notation:\n", - "```python\n", - "m.fs.flash.inlet.flow_mol.fix(1.0)\n", - "```\n", - "\n", - "To specify variables that are indexed by components, you can use the following notation:\n", - "```python\n", - "m.fs.flash.inlet.mole_frac_comp[0, \"benzene\"].fix(0.5)\n", - "```\n", - "\n", - "
\n", - "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", - "
\n", - "\n", - "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", - "\n", - "\n", - "To specify the value of a variable on the unit itself, use the following notation.\n", - "\n", - "```python\n", - "m.fs.flash.heat_duty.fix(0)\n", - "```\n", - "\n", - "For this module, we will use the following specifications:\n", - "* inlet overall molar flow = 1.0 (`flow_mol`)\n", - "* inlet temperature = 368 K (`temperature`)\n", - "* inlet pressure = 101325 Pa (`pressure`)\n", - "* inlet mole fraction (benzene) = 0.5 (`mole_frac_comp[0, \"benzene\"]`)\n", - "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", - "* The heat duty on the flash set to 0 (`heat_duty`)\n", - "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Write the code below to specify the inlet conditions and unit specifications described above\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [], - "source": [ - "# Todo: Add inlet specifications given above\n", - "m.fs.flash.inlet.flow_mol.fix(1)\n", - "m.fs.flash.inlet.temperature.fix(368)\n", - "m.fs.flash.inlet.pressure.fix(101325)\n", - "m.fs.flash.inlet.mole_frac_comp[0, \"benzene\"].fix(0.5)\n", - "m.fs.flash.inlet.mole_frac_comp[0, \"toluene\"].fix(0.5)\n", - "\n", - "# Todo: Add 2 flash unit specifications given above\n", - "m.fs.flash.heat_duty.fix(0)\n", - "m.fs.flash.deltaP.fix(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Check the degrees of freedom again to ensure that the system is now square. You should see that the degrees of freedom is now 0.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Degrees of Freedom = 0\n" - ] - } - ], - "source": [ - "# Todo: print the degrees of freedom for your model\n", - "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Initializing the Model\n", - "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - Optimal Solution Found.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_out: State Released.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume: Initialization Complete\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash.control_volume.properties_in: State Released.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2023-11-02 10:30:25 [INFO] idaes.init.fs.flash: Initialization Complete: optimal - Optimal Solution Found\n" - ] - } - ], - "source": [ - "# Todo: initialize the flash unit\n", - "m.fs.flash.initialize(outlvl=idaeslog.INFO)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: \n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 135\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 72\n", - "\n", - "Total number of variables............................: 41\n", - " variables with only lower bounds: 3\n", - " variables with lower and upper bounds: 10\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 41\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 1.46e-11 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - "\n", - "Number of Iterations....: 0\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 5.6292494973376915e-12 1.4551915228366852e-11\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 5.6292494973376915e-12 1.4551915228366852e-11\n", - "\n", - "\n", - "Number of objective function evaluations = 1\n", - "Number of objective gradient evaluations = 1\n", - "Number of equality constraint evaluations = 1\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 1\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 0\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.000\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n", - "\b\b\b\b\b\b\b\b\b\b\b\b\b\b" - ] - } - ], - "source": [ - "# Todo: create the ipopt solver\n", - "solver = SolverFactory(\"ipopt\")\n", - "\n", - "# Todo: solve the model\n", - "status = solver.solve(m, tee=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Viewing the Results\n", - "\n", - "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", - "```python\n", - "print('Vap. Outlet Temperature = ', value(m.fs.flash.vap_outlet.temperature[0]))\n", - "```\n", - "\n", - "You can also find more information about a variable or an entire port using the `display` method from Pyomo:\n", - "```python\n", - "m.fs.flash.vap_outlet.temperature.display()\n", - "m.fs.flash.vap_outlet.display()\n", - "```\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the cells below to show the current value of the flash vapor outlet pressure. This cell also shows use of the display function to see the values of the variables in the vap_outlet and the liq_outlet.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Pressure = 101325.0\n", - "\n", - "Output from display:\n", - "vap_outlet : Size=1\n", - " Key : Name : Value\n", - " None : flow_mol : {0.0: 0.39611817487741735}\n", - " : mole_frac_comp : {(0.0, 'benzene'): 0.6339766485081294, (0.0, 'toluene'): 0.36602335149187054}\n", - " : pressure : {0.0: 101325.0}\n", - " : temperature : {0.0: 368.0}\n", - "liq_outlet : Size=1\n", - " Key : Name : Value\n", - " None : flow_mol : {0.0: 0.6038818251225827}\n", - " : mole_frac_comp : {(0.0, 'benzene'): 0.4121175977229309, (0.0, 'toluene'): 0.587882402277069}\n", - " : pressure : {0.0: 101325.0}\n", - " : temperature : {0.0: 368.0}\n" - ] - } - ], - "source": [ - "# Print the pressure of the flash vapor outlet\n", - "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", - "\n", - "print()\n", - "print(\"Output from display:\")\n", - "# Call display on vap_outlet and liq_outlet of the flash\n", - "m.fs.flash.vap_outlet.display()\n", - "m.fs.flash.liq_outlet.display()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.flash Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 0.0000 : watt : True : (None, None)\n", - " Pressure Change : 0.0000 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " flow_mol mole / second 1.0000 0.39612 0.60388 \n", - " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", - " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", - " temperature kelvin 368.00 368.00 368.00 \n", - " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", - "====================================================================================\n" - ] - } - ], - "source": [ - "m.fs.flash.report()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Studying Purity as a Function of Heat Duty\n", - "\n", - "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", - "\n", - "First, let's import the matplotlib package for plotting as we did in the previous module.\n", - "
\n", - "Inline Exercise:\n", - "Execute the cell below to import matplotlib appropriately.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Exercise specifications:\n", - "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", - "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "scrolled": true, - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulating with Q = -17000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -16142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -15285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -14428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -13571.428571428572\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -12714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -11857.142857142857\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -11000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -10142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -9285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -8428.57142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -7571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -6714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -5857.142857142857\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -5000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -4142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -3285.7142857142862\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -2428.5714285714294\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -1571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -714.2857142857156\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 142.8571428571413\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 1000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 1857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 2714.2857142857138\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 3571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 4428.5714285714275\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 5285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 6142.857142857141\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 7000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 7857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 8714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 9571.428571428569\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 10428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 11285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 12142.857142857141\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 13000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 13857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 14714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 15571.428571428569\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 16428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 17285.714285714283\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 18142.857142857145\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 19000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 19857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 20714.28571428571\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 21571.428571428572\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 22428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 23285.714285714283\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 24142.857142857145\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 25000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" + "cells": [ + { + "cell_type": "code", + "metadata": { + "tags": [ + "header", + "hide-cell" + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } + }, + "source": [ + "###############################################################################\n", + "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", + "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Design of Advanced Energy Systems (IDAES).\n", + "#\n", + "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", + "# University of California, through Lawrence Berkeley National Laboratory,\n", + "# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon\n", + "# University, West Virginia University Research Corporation, et al.\n", + "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", + "# for full copyright and license information.\n", + "###############################################################################" + ], + "outputs": [], + "execution_count": 1 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "# Flash Unit Model Tutorial\n", + "\n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", + "\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", + "\n", + "## Key links to documentation\n", + "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" ] - }, - "metadata": { - "filenames": { - "image/png": "C:\\Users\\dkgun\\src\\dangunter\\examples\\idaes_examples\\notebooks\\_build\\jupyter_execute\\docs\\tut\\core\\flash_unit_doc_33_51.png" - } - }, - "output_type": "display_data" - } - ], - "source": [ - "# import the solve_successful checking function from workshop tools\n", - "from idaes_examples.mod.tut.workshoptools import solve_successful\n", - "\n", - "# Todo: import numpy\n", - "import numpy as np\n", - "\n", - "# create the empty lists to store the results that will be plotted\n", - "Q = []\n", - "V = []\n", - "\n", - "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", - "\n", - "# Todo: Write the for loop specification using numpy's linspace\n", - "for duty in np.linspace(-17000, 25000, 50):\n", - " # fix the heat duty\n", - " m.fs.flash.heat_duty.fix(duty)\n", - "\n", - " # append the value of the duty to the Q list\n", - " Q.append(duty)\n", - "\n", - " # print the current simulation\n", - " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", - "\n", - " # Solve the model\n", - " status = solver.solve(m)\n", - "\n", - " # append the value for vapor fraction if the solve was successful\n", - " if solve_successful(status):\n", - " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", - " print(\"... solve successful.\")\n", - " else:\n", - " V.append(0.0)\n", - " print(\"... solve failed.\")\n", - "\n", - "# Create and show the figure\n", - "plt.figure(\"Vapor Fraction\")\n", - "plt.plot(Q, V)\n", - "plt.grid()\n", - "plt.xlabel(\"Heat Duty [J]\")\n", - "plt.ylabel(\"Vapor Fraction [-]\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Repeat the exercise above, but create a figure showing the heat duty vs. the mole fraction of Benzene in the vapor outlet. Remove any unnecessary printing to create cleaner results.\n", - "
" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulating with Q = -17000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -16142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -15285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -14428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -13571.428571428572\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -12714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -11857.142857142857\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -11000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -10142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -9285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -8428.57142857143\n" - ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -7571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -6714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -5857.142857142857\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -5000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -4142.857142857143\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -3285.7142857142862\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -2428.5714285714294\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -1571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = -714.2857142857156\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 142.8571428571413\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 1000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 1857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 2714.2857142857138\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 3571.4285714285725\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 4428.5714285714275\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 5285.714285714286\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 6142.857142857141\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 7000.0\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 7857.142857142855\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 8714.285714285714\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 9571.428571428569\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 10428.571428571428\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 11285.714285714286\n" - ] + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", + "\n", + "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", + "\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the cell below to perform the imports. Let a workshop organizer know if you see any errors.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 12142.857142857141\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, + "cell_type": "code", + "source": [ + "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", + "from idaes.core import FlowsheetBlock\n", + "\n", + "# Import idaes logger to set output levels\n", + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the cell below to create the objects\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 13000.0\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, + "cell_type": "code", + "source": [ + "m = ConcreteModel()\n", + "m.fs = FlowsheetBlock(dynamic=False)" + ], + "outputs": [], + "execution_count": 3 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.577500Z", + "start_time": "2025-06-06T16:45:49.572256Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: call pprint on the model\n", + "m.pprint()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Block Declarations\n", + " fs : Size=1, Index=None, Active=True\n", + " 1 Set Declarations\n", + " _time : Size=1, Index=None, Ordered=Insertion\n", + " Key : Dimen : Domain : Size : Members\n", + " None : 1 : Any : 1 : {0.0,}\n", + "\n", + " 1 Declarations: _time\n", + "\n", + "1 Declarations: fs\n" + ] + } + ], + "execution_count": 5 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 2.1 Define Properties\n", + "\n", + "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", + "\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", + "\n", + "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import and create the properties block.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 13857.142857142855\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, + "cell_type": "code", + "source": [ + "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", + " BTXParameterBlock,\n", + ")" + ], + "outputs": [], + "execution_count": 6 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, + "cell_type": "code", + "source": [ + "m.fs.properties = BTXParameterBlock(\n", + " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", + ")" + ], + "outputs": [], + "execution_count": 7 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 2.2 Adding Flash Unit\n", + "\n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", + "\n", + "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", + "\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", + "\n", + "Some of the IDAES pre-written unit models:\n", + "* Mixer / Splitter\n", + "* Heater / Cooler\n", + "* Heat Exchangers (simple and 1D discretized)\n", + "* Flash\n", + "* Reactors (kinetic, equilibrium, gibbs, stoichiometric conversion)\n", + "* Pressure changing equipment (compressors, expanders, pumps)\n", + "* Feed and Product (source / sink) components\n", + "\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the Flash and create an instance of the unit model, attaching it to the flowsheet object.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 14714.285714285714\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, + "cell_type": "code", + "source": "from idaes.models.unit_models import Flash", + "outputs": [], + "execution_count": 8 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, + "cell_type": "code", + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", + "outputs": [], + "execution_count": 9 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 15571.428571428569\n" - ] + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", + "\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 16428.571428571428\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 17285.714285714283\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } + }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], + "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 4 Set Operating Conditions\n", + "\n", + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", + "\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", + "\n", + "\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 18142.857142857145\n" - ] + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.1 Degrees of Freedom\n", + "\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", + "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 19000.0\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.240605Z", + "start_time": "2025-06-06T16:45:50.237594Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "# Todo: Call the python help on the degrees_of_freedom function\n", + "help(degrees_of_freedom)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", + "\n", + "degrees_of_freedom(block)\n", + " Method to return the degrees of freedom of a model.\n", + "\n", + " Args:\n", + " block : model to be studied\n", + "\n", + " Returns:\n", + " Number of degrees of freedom in block.\n", + "\n" + ] + } + ], + "execution_count": 16 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.297399Z", + "start_time": "2025-06-06T16:45:50.291352Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: print the degrees of freedom for your model\n", + "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 7\n" + ] + } + ], + "execution_count": 18 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", + "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", + "\n", + "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", + "\n", + "As an example, to fix the molar flow of the inlet to be 1.0, you can use the following notation:\n", + "```python\n", + "m.fs.flash.inlet.flow_mol.fix(1.0)\n", + "```\n", + "\n", + "To specify variables that are indexed by components, you can use the following notation:\n", + "```python\n", + "m.fs.flash.inlet.mole_frac_comp[0, \"benzene\"].fix(0.5)\n", + "```\n", + "\n", + "
\n", + "Note:\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", + "
\n", + "\n", + "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", + "\n", + "\n", + "To specify the value of a variable on the unit itself, use the following notation.\n", + "\n", + "```python\n", + "m.fs.flash.heat_duty.fix(0)\n", + "```\n", + "\n", + "For this module, we will use the following specifications:\n", + "* inlet overall molar flow = 1.0 (`flow_mol`)\n", + "* inlet temperature = 368 K (`temperature`)\n", + "* inlet pressure = 101325 Pa (`pressure`)\n", + "* inlet mole fraction (benzene) = 0.5 (`mole_frac_comp[0, \"benzene\"]`)\n", + "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", + "* The heat duty on the flash set to 0 (`heat_duty`)\n", + "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", + "\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 19857.142857142855\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.396800Z", + "start_time": "2025-06-06T16:45:50.392314Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: Add inlet specifications given above\n", + "m.fs.flash.inlet.flow_mol.fix(1)\n", + "m.fs.flash.inlet.temperature.fix(368)\n", + "m.fs.flash.inlet.pressure.fix(101325)\n", + "m.fs.flash.inlet.mole_frac_comp[0, \"benzene\"].fix(0.5)\n", + "m.fs.flash.inlet.mole_frac_comp[0, \"toluene\"].fix(0.5)\n", + "\n", + "# Todo: Add 2 flash unit specifications given above\n", + "m.fs.flash.heat_duty.fix(0)\n", + "m.fs.flash.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 20714.28571428571\n" - ] + "metadata": { + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 0\n" + ] + } + ], + "execution_count": 23, + "source": [ + "# Todo: print the degrees of freedom for your model\n", + "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 21571.428571428572\n" - ] + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 5 Initializing the Model\n", + "\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", + "\n", + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 22428.571428571428\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:51:40.247234Z", + "start_time": "2025-06-06T16:51:39.730044Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: initialize the flash unit\n", + "FlashInitializer = m.fs.flash.default_initializer()\n", + "FlashInitializer.initialize(m.fs.flash)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 33 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 6 Solving the Model\n", + "\n", + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 23285.714285714283\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.439966Z", + "start_time": "2025-06-06T17:04:32.396984Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: create the ipopt solver\n", + "solver = SolverFactory(\"ipopt\")\n", + "\n", + "# Todo: solve the model\n", + "status = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 135\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 41\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.22e-05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e-11 1.00e-02 -1.0 6.22e-05 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 1\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 37 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 7 Viewing the Results\n", + "\n", + "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", + "```python\n", + "print('Vap. Outlet Temperature = ', value(m.fs.flash.vap_outlet.temperature[0]))\n", + "```\n", + "\n", + "You can also find more information about a variable or an entire port using the `display` method from Pyomo:\n", + "```python\n", + "m.fs.flash.vap_outlet.temperature.display()\n", + "m.fs.flash.vap_outlet.display()\n", + "```\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the cells below to show the current value of the flash vapor outlet pressure. This cell also shows use of the display function to see the values of the variables in the vap_outlet and the liq_outlet.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 24142.857142857145\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, + "cell_type": "code", + "source": [ + "# Print the pressure of the flash vapor outlet\n", + "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", + "\n", + "print()\n", + "print(\"Output from display:\")\n", + "# Call display on vap_outlet and liq_outlet of the flash\n", + "m.fs.flash.vap_outlet.display()\n", + "m.fs.flash.liq_outlet.display()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n", - "Simulating with Q = 25000.0\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, + "cell_type": "code", + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## Exercise: Studying Purity as a Function of Heat Duty\n", + "\n", + "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", + "\n", + "First, let's import the matplotlib package for plotting as we did in the previous module.\n", + "
\n", + "Inline Exercise:\n", + "Execute the cell below to import matplotlib appropriately.\n", + "
" + ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "... solve successful.\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, + "cell_type": "code", + "source": "import matplotlib.pyplot as plt", + "outputs": [], + "execution_count": 42 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Exercise specifications:\n", + "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", + "* Specify the heat duty from -17000 to 25000 over 50 steps\n", + "\n" + ] }, { - "data": { - "image/png": "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", - "text/plain": [ - "
" + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:48.800601Z", + "start_time": "2025-06-06T17:04:46.438264Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# import the solve_successful checking function from workshop tools\n", + "from idaes_examples.mod.tut.workshoptools import solve_successful\n", + "\n", + "# Todo: import numpy\n", + "import numpy as np\n", + "\n", + "# create the empty lists to store the results that will be plotted\n", + "Q = []\n", + "V = []\n", + "\n", + "# re-initialize model\n", + "FlashInitializer.initialize(m.fs.flash)\n", + "\n", + "# Todo: Write the for loop specification using numpy's linspace\n", + "for duty in np.linspace(-17000, 25000, 50):\n", + " # fix the heat duty\n", + " m.fs.flash.heat_duty.fix(duty)\n", + "\n", + " # append the value of the duty to the Q list\n", + " Q.append(duty)\n", + "\n", + " # print the current simulation\n", + " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", + "\n", + " # Solve the model\n", + " status = solver.solve(m)\n", + "\n", + " # append the value for vapor fraction if the solve was successful\n", + " if solve_successful(status):\n", + " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", + " print(\"... solve successful.\")\n", + " else:\n", + " V.append(0.0)\n", + " print(\"... solve failed.\")\n", + "\n", + "# Create and show the figure\n", + "plt.figure(\"Vapor Fraction\")\n", + "plt.plot(Q, V)\n", + "plt.grid()\n", + "plt.xlabel(\"Heat Duty [J]\")\n", + "plt.ylabel(\"Vapor Fraction [-]\")\n", + "plt.show()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 43 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:02.101331Z", + "start_time": "2025-06-06T17:05:00.157447Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", + "Q = []\n", + "V = []\n", + "\n", + "for duty in np.linspace(-17000, 25000, 50):\n", + " # fix the heat duty\n", + " m.fs.flash.heat_duty.fix(duty)\n", + "\n", + " # append the value of the duty to the Q list\n", + " Q.append(duty)\n", + "\n", + " # print the current simulation\n", + " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", + "\n", + " # solve the model\n", + " status = solver.solve(m)\n", + "\n", + " # append the value for vapor fraction if the solve was successful\n", + " if solve_successful(status):\n", + " V.append(value(m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]))\n", + " print(\"... solve successful.\")\n", + " else:\n", + " V.append(0.0)\n", + " print(\"... solve failed.\")\n", + "\n", + "plt.figure(\"Purity\")\n", + "plt.plot(Q, V)\n", + "plt.grid()\n", + "plt.xlabel(\"Heat Duty [J]\")\n", + "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", + "plt.show()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 44 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", + "\n", + "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", + "\n", + "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", + "\n" ] - }, - "metadata": { - "filenames": { - "image/png": "C:\\Users\\dkgun\\src\\dangunter\\examples\\idaes_examples\\notebooks\\_build\\jupyter_execute\\docs\\tut\\core\\flash_unit_doc_35_51.png" - } - }, - "output_type": "display_data" - } - ], - "source": [ - "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", - "Q = []\n", - "V = []\n", - "\n", - "for duty in np.linspace(-17000, 25000, 50):\n", - " # fix the heat duty\n", - " m.fs.flash.heat_duty.fix(duty)\n", - "\n", - " # append the value of the duty to the Q list\n", - " Q.append(duty)\n", - "\n", - " # print the current simulation\n", - " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", - "\n", - " # solve the model\n", - " status = solver.solve(m)\n", - "\n", - " # append the value for vapor fraction if the solve was successful\n", - " if solve_successful(status):\n", - " V.append(value(m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]))\n", - " print(\"... solve successful.\")\n", - " else:\n", - " V.append(0.0)\n", - " print(\"... solve failed.\")\n", - "\n", - "plt.figure(\"Purity\")\n", - "plt.plot(Q, V)\n", - "plt.grid()\n", - "plt.xlabel(\"Heat Duty [J]\")\n", - "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", - "\n", - "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", - "\n", - "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", - "
\n" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "tags": [ - "solution" - ] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ipopt 3.13.2: \n", - "\n", - "******************************************************************************\n", - "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", - " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", - " For more information visit http://projects.coin-or.org/Ipopt\n", - "\n", - "This version of Ipopt was compiled from source code available at\n", - " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", - " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", - " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", - "\n", - "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", - " for large-scale scientific computation. All technical papers, sales and\n", - " publicity material resulting from use of the HSL codes within IPOPT must\n", - " contain the following acknowledgement:\n", - " HSL, a collection of Fortran codes for large-scale scientific\n", - " computation. See http://www.hsl.rl.ac.uk.\n", - "******************************************************************************\n", - "\n", - "This is Ipopt version 3.13.2, running with linear solver ma27.\n", - "\n", - "Number of nonzeros in equality constraint Jacobian...: 137\n", - "Number of nonzeros in inequality constraint Jacobian.: 0\n", - "Number of nonzeros in Lagrangian Hessian.............: 72\n", - "\n", - "Total number of variables............................: 42\n", - " variables with only lower bounds: 3\n", - " variables with lower and upper bounds: 10\n", - " variables with only upper bounds: 0\n", - "Total number of equality constraints.................: 42\n", - "Total number of inequality constraints...............: 0\n", - " inequality constraints with only lower bounds: 0\n", - " inequality constraints with lower and upper bounds: 0\n", - " inequality constraints with only upper bounds: 0\n", - "\n", - "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", - " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", - " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", - " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", - " 3 0.0000000e+00 6.95e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", - "\n", - "Number of Iterations....: 3\n", - "\n", - " (scaled) (unscaled)\n", - "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Constraint violation....: 8.9144743362344083e-11 6.9545421865768731e-08\n", - "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", - "Overall NLP error.......: 8.9144743362344083e-11 6.9545421865768731e-08\n", - "\n", - "\n", - "Number of objective function evaluations = 4\n", - "Number of objective gradient evaluations = 4\n", - "Number of equality constraint evaluations = 4\n", - "Number of inequality constraint evaluations = 0\n", - "Number of equality constraint Jacobian evaluations = 4\n", - "Number of inequality constraint Jacobian evaluations = 0\n", - "Number of Lagrangian Hessian evaluations = 3\n", - "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", - "Total CPU secs in NLP function evaluations = 0.000\n", - "\n", - "EXIT: Optimal Solution Found.\n", - "\b\b\b\b\b\b\b\b\b\b\b\b\b\b" - ] }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "====================================================================================\n", - "Unit : fs.flash Time: 0.0\n", - "------------------------------------------------------------------------------------\n", - " Unit Performance\n", - "\n", - " Variables: \n", - "\n", - " Key : Value : Units : Fixed : Bounds\n", - " Heat Duty : 5083.6 : watt : False : (None, None)\n", - " Pressure Change : 0.0000 : pascal : True : (None, None)\n", - "\n", - "------------------------------------------------------------------------------------\n", - " Stream Table\n", - " Units Inlet Vapor Outlet Liquid Outlet\n", - " flow_mol mole / second 1.0000 0.54833 0.45167 \n", - " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", - " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", - " temperature kelvin 368.00 369.07 369.07 \n", - " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", - "====================================================================================\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.768445Z", + "start_time": "2025-06-06T17:05:05.378930Z" + }, + "tags": [ + "solution" + ] + }, + "cell_type": "code", + "source": [ + "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", + "m.fs.flash.heat_duty.fix(0)\n", + "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "\n", + "# Unfix the heat_duty variable\n", + "m.fs.flash.heat_duty.unfix()\n", + "\n", + "# Todo: Add a new constraint (benzene mole fraction to 0.6)\n", + "m.benz_purity_con = Constraint(\n", + " expr=m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"] == 0.6\n", + ")\n", + "\n", + "# solve the problem\n", + "status = solver.solve(m, tee=True)\n", + "\n", + "# Check stream condition\n", + "m.fs.flash.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 137\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 42\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", + " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 6.96e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 5083.6 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.54833 0.45167 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", + " temperature kelvin 368.00 369.07 369.07 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 46 + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.12" } - ], - "source": [ - "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", - "m.fs.flash.heat_duty.fix(0)\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", - "\n", - "# Unfix the heat_duty variable\n", - "m.fs.flash.heat_duty.unfix()\n", - "\n", - "# Todo: Add a new constraint (benzene mole fraction to 0.6)\n", - "m.benz_purity_con = Constraint(\n", - " expr=m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"] == 0.6\n", - ")\n", - "\n", - "# solve the problem\n", - "status = solver.solve(m, tee=True)\n", - "\n", - "# Check stream condition\n", - "m.fs.flash.report()" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 3 -} + "nbformat": 4, + "nbformat_minor": 3 +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit_exercise.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit_exercise.ipynb index 19e3b691..7896bd57 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit_exercise.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit_exercise.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -23,41 +25,50 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "# Flash Unit Model\n", + "# Flash Unit Model Tutorial\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "## Key links to documentation\n", "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", "\n", "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", "\n", "
\n", "Inline Exercise:\n", @@ -66,23 +77,32 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", "from idaes.core import FlowsheetBlock\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -91,20 +111,29 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 3 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", + "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block. Lets use the `m.pprint()` to investigate the current contents of the model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -113,27 +142,29 @@ ] }, { - "cell_type": "code", - "execution_count": 3, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.531374Z", + "start_time": "2025-06-06T16:45:49.527521Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: call pprint on the model", "outputs": [], - "source": [ - "# Todo: call pprint on the model" - ] + "execution_count": 4 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Define Properties\n", + "### 2.1 Define Properties\n", "\n", "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", "\n", "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", "\n", @@ -144,38 +175,48 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", " BTXParameterBlock,\n", ")" - ] + ], + "outputs": [], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "m.fs.properties = BTXParameterBlock(\n", " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", ")" - ] + ], + "outputs": [], + "execution_count": 7 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Adding Flash Unit\n", + "### 2.2 Adding Flash Unit\n", "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", "\n", "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", "\n", "Some of the IDAES pre-written unit models:\n", "* Mixer / Splitter\n", @@ -186,7 +227,7 @@ "* Pressure changing equipment (compressors, expanders, pumps)\n", "* Feed and Product (source / sink) components\n", "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", "\n", "
\n", "Inline Exercise:\n", @@ -195,40 +236,183 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "source": "from idaes.models.unit_models import Flash", "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] + "execution_count": 8 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, "cell_type": "code", - "execution_count": 8, + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", + "outputs": [], + "execution_count": 9 + }, + { "metadata": {}, + "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.783706Z", + "start_time": "2025-06-06T16:45:49.781688Z" + }, + "tags": [ + "noauto" + ] + }, + "cell_type": "code", + "source": "m.pprint()", "outputs": [], + "execution_count": 10 + }, + { + "metadata": {}, + "cell_type": "markdown", "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" ] }, { + "metadata": {}, "cell_type": "markdown", + "source": [ + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", + "\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", + "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } + }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], + "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, "cell_type": "markdown", + "source": "" + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "## Set Operating Conditions\n", + "## 4 Set Operating Conditions\n", "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", "\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.1 Degrees of Freedom\n", + "\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", + "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", @@ -236,24 +420,32 @@ ] }, { - "cell_type": "code", - "execution_count": 9, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.224457Z", + "start_time": "2025-06-06T16:45:50.221905Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function" - ] + ], + "outputs": [], + "execution_count": 15 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -262,22 +454,26 @@ ] }, { - "cell_type": "code", - "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.271361Z", + "start_time": "2025-06-06T16:45:50.268763Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: print the degrees of freedom for your model", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 17 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", "\n", "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", @@ -294,7 +490,7 @@ "\n", "
\n", "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", "
\n", "\n", "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", @@ -314,7 +510,17 @@ "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", "* The heat duty on the flash set to 0 (`heat_duty`)\n", "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Write the code below to specify the inlet conditions and unit specifications described above\n", @@ -322,24 +528,40 @@ ] }, { - "cell_type": "code", - "execution_count": 14, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.360852Z", + "start_time": "2025-06-06T16:45:50.357341Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "\n", "\n", "# Todo: Add 2 flash unit specifications given above" + ], + "outputs": [], + "execution_count": 20 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" ] }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -348,51 +570,79 @@ ] }, { - "cell_type": "code", - "execution_count": 16, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 22, + "source": "# Todo: print the degrees of freedom for your model" }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Initializing the Model\n", + "## 5 Initializing the Model\n", "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", "\n", + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", + "Define the initializer instance, and initialize the flash unit model\n", "
" ] }, { - "cell_type": "code", - "execution_count": 19, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.499945Z", + "start_time": "2025-06-06T16:45:50.497439Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: initialize the flash unit", "outputs": [], - "source": [ - "# Todo: initialize the flash unit" - ] + "execution_count": 25 }, { + "metadata": {}, "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", + "## 6 Solving the Model\n", "\n", + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", @@ -400,25 +650,29 @@ ] }, { - "cell_type": "code", - "execution_count": 21, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.219172Z", + "start_time": "2025-06-06T17:04:32.216161Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "\n", "# Todo: solve the model" - ] + ], + "outputs": [], + "execution_count": 36 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Viewing the Results\n", + "## 7 Viewing the Results\n", "\n", "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", "```python\n", @@ -438,10 +692,13 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], "source": [ "# Print the pressure of the flash vapor outlet\n", "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", @@ -451,34 +708,89 @@ "# Call display on vap_outlet and liq_outlet of the flash\n", "m.fs.flash.vap_outlet.display()\n", "m.fs.flash.liq_outlet.display()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", "\n", "
\n", "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash.report()" - ] + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Studying Purity as a Function of Heat Duty\n", + "## Exercise: Studying Purity as a Function of Heat Duty\n", "\n", "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", "\n", @@ -490,22 +802,35 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "source": "import matplotlib.pyplot as plt", "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] + "execution_count": 42 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Exercise specifications:\n", "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", @@ -513,14 +838,12 @@ ] }, { - "cell_type": "code", - "execution_count": 29, "metadata": { "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -533,22 +856,22 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "UnitModelInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "\n", " # fix the heat duty\n", " m.fs.flash.heat_duty.fix(duty)\n", - " \n", + "\n", " # append the value of the duty to the Q list\n", " Q.append(duty)\n", - " \n", + "\n", " # print the current simulation\n", " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", "\n", " # Solve the model\n", " status = solver.solve(m)\n", - " \n", + "\n", " # append the value for vapor fraction if the solve was successful\n", " if solve_successful(status):\n", " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", @@ -556,7 +879,7 @@ " else:\n", " V.append(0.0)\n", " print('... solve failed.')\n", - " \n", + "\n", "# Create and show the figure\n", "plt.figure(\"Vapor Fraction\")\n", "plt.plot(Q, V)\n", @@ -564,11 +887,17 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [], + "execution_count": null }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -577,28 +906,36 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor", "outputs": [], - "source": [ - "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor" - ] + "execution_count": null }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", "\n", "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", "\n", "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", @@ -606,14 +943,16 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.363302Z", + "start_time": "2025-06-06T17:05:04.960601Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -629,7 +968,106 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 136\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.07e-08 1.01e-04 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e+00 2.42e-01 -1.0 4.86e+02 - 9.90e-01 1.00e+00f 1\n", + " 2 0.0000000e+00 5.55e+01 5.60e-03 -1.0 3.00e+03 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 1.91e+00 4.24e-05 -1.0 5.68e+02 - 1.00e+00 1.00e+00h 1\n", + " 4 0.0000000e+00 1.53e-05 1.90e-06 -2.5 1.35e+00 - 1.00e+00 1.00e+00h 1\n", + " 5 0.0000000e+00 4.66e-10 1.50e-09 -3.8 8.72e-03 - 1.00e+00 1.00e+00h 1\n", + " 6 0.0000000e+00 2.18e-11 1.84e-11 -5.7 1.92e-03 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 1.46e-11 2.51e-14 -8.6 2.10e-04 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 7\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 2.5059035640133008e-14 2.5059035640133008e-14\n", + "Constraint violation....: 4.8801876740451558e-13 1.4551915228366852e-11\n", + "Complementarity.........: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "Overall NLP error.......: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 9\n", + "Number of objective gradient evaluations = 8\n", + "Number of equality constraint evaluations = 9\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 8\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 7\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 4059.3 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.51773 0.48227 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60690 0.38524 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.39310 0.61476 \n", + " temperature kelvin 368.00 368.85 368.85 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 45 } ], "metadata": { @@ -654,4 +1092,4 @@ }, "nbformat": 4, "nbformat_minor": 3 -} +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit_solution.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit_solution.ipynb index 6b4b3752..9cb8329c 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit_solution.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit_solution.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -23,41 +25,50 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "# Flash Unit Model\n", + "# Flash Unit Model Tutorial\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "## Key links to documentation\n", "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", "\n", "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", "\n", "
\n", "Inline Exercise:\n", @@ -66,23 +77,32 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", "from idaes.core import FlowsheetBlock\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -91,20 +111,29 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 3 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", + "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block. Lets use the `m.pprint()` to investigate the current contents of the model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -113,41 +142,64 @@ ] }, { - "cell_type": "code", - "execution_count": 3, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.531374Z", + "start_time": "2025-06-06T16:45:49.527521Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: call pprint on the model", "outputs": [], - "source": [ - "# Todo: call pprint on the model" - ] + "execution_count": 4 }, { - "cell_type": "code", - "execution_count": 4, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.577500Z", + "start_time": "2025-06-06T16:45:49.572256Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: call pprint on the model\n", "m.pprint()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Block Declarations\n", + " fs : Size=1, Index=None, Active=True\n", + " 1 Set Declarations\n", + " _time : Size=1, Index=None, Ordered=Insertion\n", + " Key : Dimen : Domain : Size : Members\n", + " None : 1 : Any : 1 : {0.0,}\n", + "\n", + " 1 Declarations: _time\n", + "\n", + "1 Declarations: fs\n" + ] + } + ], + "execution_count": 5 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Define Properties\n", + "### 2.1 Define Properties\n", "\n", "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", "\n", "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", "\n", @@ -158,38 +210,48 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", " BTXParameterBlock,\n", ")" - ] + ], + "outputs": [], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "m.fs.properties = BTXParameterBlock(\n", " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", ")" - ] + ], + "outputs": [], + "execution_count": 7 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Adding Flash Unit\n", + "### 2.2 Adding Flash Unit\n", "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", "\n", "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", "\n", "Some of the IDAES pre-written unit models:\n", "* Mixer / Splitter\n", @@ -200,7 +262,7 @@ "* Pressure changing equipment (compressors, expanders, pumps)\n", "* Feed and Product (source / sink) components\n", "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", "\n", "
\n", "Inline Exercise:\n", @@ -209,40 +271,183 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "source": "from idaes.models.unit_models import Flash", "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] + "execution_count": 8 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, "cell_type": "code", - "execution_count": 8, + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", + "outputs": [], + "execution_count": 9 + }, + { "metadata": {}, + "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.783706Z", + "start_time": "2025-06-06T16:45:49.781688Z" + }, + "tags": [ + "noauto" + ] + }, + "cell_type": "code", + "source": "m.pprint()", "outputs": [], + "execution_count": 10 + }, + { + "metadata": {}, + "cell_type": "markdown", "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" ] }, { + "metadata": {}, "cell_type": "markdown", + "source": [ + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", + "\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", + "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } + }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], + "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, "cell_type": "markdown", + "source": "" + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "## Set Operating Conditions\n", + "## 4 Set Operating Conditions\n", + "\n", + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", + "\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.1 Degrees of Freedom\n", "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", @@ -250,41 +455,71 @@ ] }, { - "cell_type": "code", - "execution_count": 9, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.224457Z", + "start_time": "2025-06-06T16:45:50.221905Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function" - ] + ], + "outputs": [], + "execution_count": 15 }, { - "cell_type": "code", - "execution_count": 10, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.240605Z", + "start_time": "2025-06-06T16:45:50.237594Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function\n", "help(degrees_of_freedom)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", + "\n", + "degrees_of_freedom(block)\n", + " Method to return the degrees of freedom of a model.\n", + "\n", + " Args:\n", + " block : model to be studied\n", + "\n", + " Returns:\n", + " Number of degrees of freedom in block.\n", + "\n" + ] + } + ], + "execution_count": 16 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -293,36 +528,52 @@ ] }, { - "cell_type": "code", - "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.271361Z", + "start_time": "2025-06-06T16:45:50.268763Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: print the degrees of freedom for your model", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 17 }, { - "cell_type": "code", - "execution_count": 12, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.297399Z", + "start_time": "2025-06-06T16:45:50.291352Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 7\n" + ] + } + ], + "execution_count": 18 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", "\n", "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", @@ -339,7 +590,7 @@ "\n", "
\n", "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", "
\n", "\n", "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", @@ -359,7 +610,17 @@ "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", "* The heat duty on the flash set to 0 (`heat_duty`)\n", "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Write the code below to specify the inlet conditions and unit specifications described above\n", @@ -367,30 +628,36 @@ ] }, { - "cell_type": "code", - "execution_count": 14, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.360852Z", + "start_time": "2025-06-06T16:45:50.357341Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "\n", "\n", "# Todo: Add 2 flash unit specifications given above" - ] + ], + "outputs": [], + "execution_count": 20 }, { - "cell_type": "code", - "execution_count": 15, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.396800Z", + "start_time": "2025-06-06T16:45:50.392314Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "m.fs.flash.inlet.flow_mol.fix(1)\n", @@ -402,11 +669,25 @@ "# Todo: Add 2 flash unit specifications given above\n", "m.fs.flash.heat_duty.fix(0)\n", "m.fs.flash.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" ] }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -415,79 +696,147 @@ ] }, { - "cell_type": "code", - "execution_count": 16, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 22, + "source": "# Todo: print the degrees of freedom for your model" }, { - "cell_type": "code", - "execution_count": 17, "metadata": { "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 0\n" + ] + } + ], + "execution_count": 23, "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Initializing the Model\n", + "## 5 Initializing the Model\n", "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", "\n", + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", + "Define the initializer instance, and initialize the flash unit model\n", "
" ] }, { - "cell_type": "code", - "execution_count": 19, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.499945Z", + "start_time": "2025-06-06T16:45:50.497439Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: initialize the flash unit", "outputs": [], - "source": [ - "# Todo: initialize the flash unit" - ] + "execution_count": 25 }, { - "cell_type": "code", - "execution_count": 20, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:51:40.247234Z", + "start_time": "2025-06-06T16:51:39.730044Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: initialize the flash unit\n", - "m.fs.flash.initialize(outlvl=idaeslog.INFO)" - ] + "FlashInitializer = m.fs.flash.default_initializer()\n", + "FlashInitializer.initialize(m.fs.flash)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 33 }, { + "metadata": {}, "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", + "## 6 Solving the Model\n", "\n", + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", @@ -495,42 +844,120 @@ ] }, { - "cell_type": "code", - "execution_count": 21, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.219172Z", + "start_time": "2025-06-06T17:04:32.216161Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "\n", "# Todo: solve the model" - ] + ], + "outputs": [], + "execution_count": 36 }, { - "cell_type": "code", - "execution_count": 22, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.439966Z", + "start_time": "2025-06-06T17:04:32.396984Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "solver = SolverFactory(\"ipopt\")\n", "\n", "# Todo: solve the model\n", "status = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 135\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 41\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.22e-05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e-11 1.00e-02 -1.0 6.22e-05 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 1\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 37 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Viewing the Results\n", + "## 7 Viewing the Results\n", "\n", "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", "```python\n", @@ -550,10 +977,13 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], "source": [ "# Print the pressure of the flash vapor outlet\n", "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", @@ -563,34 +993,89 @@ "# Call display on vap_outlet and liq_outlet of the flash\n", "m.fs.flash.vap_outlet.display()\n", "m.fs.flash.liq_outlet.display()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", "\n", "
\n", "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash.report()" - ] + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Studying Purity as a Function of Heat Duty\n", + "## Exercise: Studying Purity as a Function of Heat Duty\n", "\n", "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", "\n", @@ -602,22 +1087,35 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "source": "import matplotlib.pyplot as plt", "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] + "execution_count": 42 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Exercise specifications:\n", "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", @@ -625,14 +1123,12 @@ ] }, { - "cell_type": "code", - "execution_count": 29, "metadata": { "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -645,22 +1141,22 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "UnitModelInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "\n", " # fix the heat duty\n", " m.fs.flash.heat_duty.fix(duty)\n", - " \n", + "\n", " # append the value of the duty to the Q list\n", " Q.append(duty)\n", - " \n", + "\n", " # print the current simulation\n", " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", "\n", " # Solve the model\n", " status = solver.solve(m)\n", - " \n", + "\n", " # append the value for vapor fraction if the solve was successful\n", " if solve_successful(status):\n", " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", @@ -668,7 +1164,7 @@ " else:\n", " V.append(0.0)\n", " print('... solve failed.')\n", - " \n", + "\n", "# Create and show the figure\n", "plt.figure(\"Vapor Fraction\")\n", "plt.plot(Q, V)\n", @@ -676,18 +1172,21 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [], + "execution_count": null }, { - "cell_type": "code", - "execution_count": 30, "metadata": { - "scrolled": true, + "ExecuteTime": { + "end_time": "2025-06-06T17:04:48.800601Z", + "start_time": "2025-06-06T17:04:46.438264Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -700,7 +1199,7 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "FlashInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "for duty in np.linspace(-17000, 25000, 50):\n", @@ -731,11 +1230,244 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 43 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -744,27 +1476,27 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor", "outputs": [], - "source": [ - "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor" - ] + "execution_count": null }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:02.101331Z", + "start_time": "2025-06-06T17:05:00.157447Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", "Q = []\n", @@ -797,18 +1529,247 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 44 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", "\n", "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", "\n", "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", @@ -816,14 +1777,16 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.363302Z", + "start_time": "2025-06-06T17:05:04.960601Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -839,17 +1802,118 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 136\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.07e-08 1.01e-04 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e+00 2.42e-01 -1.0 4.86e+02 - 9.90e-01 1.00e+00f 1\n", + " 2 0.0000000e+00 5.55e+01 5.60e-03 -1.0 3.00e+03 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 1.91e+00 4.24e-05 -1.0 5.68e+02 - 1.00e+00 1.00e+00h 1\n", + " 4 0.0000000e+00 1.53e-05 1.90e-06 -2.5 1.35e+00 - 1.00e+00 1.00e+00h 1\n", + " 5 0.0000000e+00 4.66e-10 1.50e-09 -3.8 8.72e-03 - 1.00e+00 1.00e+00h 1\n", + " 6 0.0000000e+00 2.18e-11 1.84e-11 -5.7 1.92e-03 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 1.46e-11 2.51e-14 -8.6 2.10e-04 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 7\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 2.5059035640133008e-14 2.5059035640133008e-14\n", + "Constraint violation....: 4.8801876740451558e-13 1.4551915228366852e-11\n", + "Complementarity.........: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "Overall NLP error.......: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 9\n", + "Number of objective gradient evaluations = 8\n", + "Number of equality constraint evaluations = 9\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 8\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 7\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 4059.3 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.51773 0.48227 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60690 0.38524 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.39310 0.61476 \n", + " temperature kelvin 368.00 368.85 368.85 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 45 }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.768445Z", + "start_time": "2025-06-06T17:05:05.378930Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -868,7 +1932,102 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 137\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 42\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", + " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 6.96e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 5083.6 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.54833 0.45167 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", + " temperature kelvin 368.00 369.07 369.07 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 46 } ], "metadata": { @@ -893,4 +2052,4 @@ }, "nbformat": 4, "nbformat_minor": 3 -} +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit_test.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit_test.ipynb index 562af431..d0a1de40 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit_test.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit_test.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -23,41 +25,50 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "# Flash Unit Model\n", + "# Flash Unit Model Tutorial\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "## Key links to documentation\n", "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", "\n", "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", "\n", "
\n", "Inline Exercise:\n", @@ -66,23 +77,32 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", "from idaes.core import FlowsheetBlock\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -91,50 +111,64 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Use the pprint method on the model, i.e. m.pprint(), to see what is currently contained in the model.\n", - "
" - ] + ], + "outputs": [], + "execution_count": 3 }, { - "cell_type": "code", - "execution_count": 4, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.577500Z", + "start_time": "2025-06-06T16:45:49.572256Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: call pprint on the model\n", "m.pprint()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Block Declarations\n", + " fs : Size=1, Index=None, Active=True\n", + " 1 Set Declarations\n", + " _time : Size=1, Index=None, Ordered=Insertion\n", + " Key : Dimen : Domain : Size : Members\n", + " None : 1 : Any : 1 : {0.0,}\n", + "\n", + " 1 Declarations: _time\n", + "\n", + "1 Declarations: fs\n" + ] + } + ], + "execution_count": 5 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Define Properties\n", + "### 2.1 Define Properties\n", "\n", "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", "\n", "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", "\n", @@ -145,38 +179,48 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", " BTXParameterBlock,\n", ")" - ] + ], + "outputs": [], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "m.fs.properties = BTXParameterBlock(\n", " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", ")" - ] + ], + "outputs": [], + "execution_count": 7 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Adding Flash Unit\n", + "### 2.2 Adding Flash Unit\n", "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", "\n", "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", "\n", "Some of the IDAES pre-written unit models:\n", "* Mixer / Splitter\n", @@ -187,7 +231,7 @@ "* Pressure changing equipment (compressors, expanders, pumps)\n", "* Feed and Product (source / sink) components\n", "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", "\n", "
\n", "Inline Exercise:\n", @@ -196,105 +240,249 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "source": "from idaes.models.unit_models import Flash", "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] + "execution_count": 8 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", "outputs": [], - "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" - ] + "execution_count": 9 }, { + "metadata": {}, "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Set Operating Conditions\n", + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", "\n", "
\n", "Inline Exercise:\n", - "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, "cell_type": "code", - "execution_count": 10, + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { "metadata": { - "tags": [ - "solution" - ] + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "" + }, + { + "metadata": {}, + "cell_type": "markdown", "source": [ - "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", - "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "## 4 Set Operating Conditions\n", "\n", - "# Todo: Call the python help on the degrees_of_freedom function\n", - "help(degrees_of_freedom)" + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", + "\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", + "\n", + "\n" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "
\n", - "Inline Exercise:\n", - "Now print the degrees of freedom for your model. The result should be 7.\n", - "
" + "### 4.1 Degrees of Freedom\n", + "\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", + "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.240605Z", + "start_time": "2025-06-06T16:45:50.237594Z" + }, + "tags": [ + "solution" + ] + }, "cell_type": "code", - "execution_count": 12, + "source": [ + "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", + "from idaes.core.util.model_statistics import degrees_of_freedom\n", + "\n", + "# Todo: Call the python help on the degrees_of_freedom function\n", + "help(degrees_of_freedom)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", + "\n", + "degrees_of_freedom(block)\n", + " Method to return the degrees of freedom of a model.\n", + "\n", + " Args:\n", + " block : model to be studied\n", + "\n", + " Returns:\n", + " Number of degrees of freedom in block.\n", + "\n" + ] + } + ], + "execution_count": 16 + }, + { "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.297399Z", + "start_time": "2025-06-06T16:45:50.291352Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 7\n" + ] + } + ], + "execution_count": 18 }, { - "cell_type": "code", - "execution_count": 13, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.334804Z", + "start_time": "2025-06-06T16:45:50.327991Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 7" - ] + ], + "outputs": [], + "execution_count": 19 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", "\n", "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", @@ -311,7 +499,7 @@ "\n", "
\n", "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", "
\n", "\n", "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", @@ -331,22 +519,20 @@ "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", "* The heat duty on the flash set to 0 (`heat_duty`)\n", "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Write the code below to specify the inlet conditions and unit specifications described above\n", - "
" + "\n" ] }, { - "cell_type": "code", - "execution_count": 15, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.396800Z", + "start_time": "2025-06-06T16:45:50.392314Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "m.fs.flash.inlet.flow_mol.fix(1)\n", @@ -358,124 +544,242 @@ "# Todo: Add 2 flash unit specifications given above\n", "m.fs.flash.heat_duty.fix(0)\n", "m.fs.flash.deltaP.fix(0)" - ] + ], + "outputs": [], + "execution_count": 21 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "
\n", - "Inline Exercise:\n", - "Check the degrees of freedom again to ensure that the system is now square. You should see that the degrees of freedom is now 0.\n", - "
" + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" ] }, { - "cell_type": "code", - "execution_count": 17, "metadata": { "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 0\n" + ] + } + ], + "execution_count": 23, "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" ] }, { - "cell_type": "code", - "execution_count": 18, "metadata": { "tags": [ "testing" ] }, + "cell_type": "code", "outputs": [], + "execution_count": 24, "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Initializing the Model\n", + "## 5 Initializing the Model\n", "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", "\n", - "
\n", - "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", - "
" + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" ] }, { - "cell_type": "code", - "execution_count": 20, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:51:40.247234Z", + "start_time": "2025-06-06T16:51:39.730044Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: initialize the flash unit\n", - "m.fs.flash.initialize(outlvl=idaeslog.INFO)" - ] + "FlashInitializer = m.fs.flash.default_initializer()\n", + "FlashInitializer.initialize(m.fs.flash)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 33 }, { + "metadata": {}, "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", + "## 6 Solving the Model\n", "\n", - "
\n", - "Inline Exercise:\n", - "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", - "
" + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" ] }, { - "cell_type": "code", - "execution_count": 22, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.439966Z", + "start_time": "2025-06-06T17:04:32.396984Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "solver = SolverFactory(\"ipopt\")\n", "\n", "# Todo: solve the model\n", "status = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 135\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 41\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.22e-05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e-11 1.00e-02 -1.0 6.22e-05 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 1\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 37 }, { - "cell_type": "code", - "execution_count": 23, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.975773Z", + "start_time": "2025-06-06T17:04:32.972754Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ - "# Check for optimal solution\n", + "# Check for an optimal solution\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert status.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 38 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Viewing the Results\n", + "## 7 Viewing the Results\n", "\n", "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", "```python\n", @@ -495,10 +799,13 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], "source": [ "# Print the pressure of the flash vapor outlet\n", "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", @@ -508,38 +815,95 @@ "# Call display on vap_outlet and liq_outlet of the flash\n", "m.fs.flash.vap_outlet.display()\n", "m.fs.flash.liq_outlet.display()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", "\n", "
\n", "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash.report()" - ] + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 }, { - "cell_type": "code", - "execution_count": 26, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:39.229802Z", + "start_time": "2025-06-06T17:04:39.132903Z" + }, "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check optimal solution values\n", "import pytest\n", @@ -563,13 +927,15 @@ ")\n", "assert value(m.fs.flash.vap_outlet.temperature[0]) == pytest.approx(368, abs=1e-3)\n", "assert value(m.fs.flash.vap_outlet.pressure[0]) == pytest.approx(101325, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 41 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Studying Purity as a Function of Heat Duty\n", + "## Exercise: Studying Purity as a Function of Heat Duty\n", "\n", "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", "\n", @@ -581,38 +947,38 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "source": "import matplotlib.pyplot as plt", "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] + "execution_count": 42 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Exercise specifications:\n", "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", - "
" + "\n" ] }, { - "cell_type": "code", - "execution_count": 30, "metadata": { - "scrolled": true, + "ExecuteTime": { + "end_time": "2025-06-06T17:04:48.800601Z", + "start_time": "2025-06-06T17:04:46.438264Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -625,7 +991,7 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "FlashInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "for duty in np.linspace(-17000, 25000, 50):\n", @@ -656,27 +1022,248 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
\n", - "Inline Exercise:\n", - "Repeat the exercise above, but create a figure showing the heat duty vs. the mole fraction of Benzene in the vapor outlet. Remove any unnecessary printing to create cleaner results.\n", - "
" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 43 }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:02.101331Z", + "start_time": "2025-06-06T17:05:00.157447Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", "Q = []\n", @@ -709,33 +1296,250 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 44 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", "\n", "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", "\n", "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", - "
\n", - "Inline Exercise:\n", - "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", - "
\n" + "\n" ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.768445Z", + "start_time": "2025-06-06T17:05:05.378930Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -754,17 +1558,110 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 137\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 42\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", + " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 6.96e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 5083.6 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.54833 0.45167 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", + " temperature kelvin 368.00 369.07 369.07 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 46 }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Check for solver status\n", "assert status.solver.termination_condition == TerminationCondition.optimal\n", @@ -789,7 +1686,9 @@ ")\n", "assert value(m.fs.flash.vap_outlet.temperature[0]) == pytest.approx(369.07, abs=1e-2)\n", "assert value(m.fs.flash.vap_outlet.pressure[0]) == pytest.approx(101325, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": null } ], "metadata": { @@ -814,4 +1713,4 @@ }, "nbformat": 4, "nbformat_minor": 3 -} +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/flash_unit_usr.ipynb b/idaes_examples/notebooks/docs/tut/core/flash_unit_usr.ipynb index 6b4b3752..9cb8329c 100644 --- a/idaes_examples/notebooks/docs/tut/core/flash_unit_usr.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/flash_unit_usr.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-06-06T16:45:45.923673Z", + "start_time": "2025-06-06T16:45:45.919855Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", @@ -23,41 +25,50 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "# Flash Unit Model\n", + "# Flash Unit Model Tutorial\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Andrew Lee \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-06-03\n", "\n", - "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene. The inlet specifications for this flash tank are:\n", + "In this module, we will familiarize ourselves with the IDAES framework by creating and working with a flowsheet that contains a single flash tank. The flash tank will be used to perform separation of Benzene and Toluene.\n", "\n", - "Inlet Specifications:\n", - "* Mole fraction (Benzene) = 0.5\n", - "* Mole fraction (Toluene) = 0.5\n", - "* Pressure = 101325 Pa\n", - "* Temperature = 368 K\n", + "The general workflow of setting up an IDAES flowsheet is the following:
\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", "\n", - "We will complete the following tasks:\n", - "* Create the model and the IDAES Flowsheet object\n", - "* Import the appropriate property packages\n", - "* Create the flash unit and set the operating conditions\n", - "* Initialize the model and simulate the system\n", - "* Demonstrate analyses on this model through some examples and exercises\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "## Key links to documentation\n", "* Main IDAES online documentation page: https://idaes-pse.readthedocs.io/en/stable/\n", - "\n", - "## Create the Model and the IDAES Flowsheet\n", + "* General Workflow: https://idaes-pse.readthedocs.io/en/stable/how_to_guides/workflow/general.html\n", + "* Flash Unit Model Documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "## 1 Import Modules\n", "\n", "In the next cell, we will perform the necessary imports to get us started. From `pyomo.environ` (a standard import for the Pyomo package), we are importing `ConcreteModel` (to create the Pyomo model that will contain the IDAES flowsheet) and `SolverFactory` (to create the object we will use to solve the equations). We will also import `Constraint` as we will be adding a constraint to the model later in the module. Lastly, we also import `value` from Pyomo. This is a function that can be used to return the current numerical value for variables and parameters in the model. These are all part of Pyomo.\n", "\n", - "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model.\n", + "We will also import the main `FlowsheetBlock` from IDAES. The flowsheet block will contain our unit model. `%matplotinline` allows plots to be displayed within the jupyter cell block output rather than in a separate window.\n", "\n", "
\n", "Inline Exercise:\n", @@ -66,23 +77,32 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.094293Z", + "start_time": "2025-06-06T16:45:45.938076Z" + } + }, "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], "source": [ "from pyomo.environ import ConcreteModel, SolverFactory, Constraint, value\n", "from idaes.core import FlowsheetBlock\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog" - ] + "import idaes.logger as idaeslog\n", + "\n", + "%matplotlib inline" + ], + "outputs": [], + "execution_count": 2 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "In the next cell, we will create the `ConcreteModel` and the `FlowsheetBlock`, and attach the flowsheet block to the Pyomo model.\n", + "## 2 Create the Model and IDAES Flowsheet\n", + "\n", + "In the next cell, we will create the `ConcreteModel` object often named `m` (which comes from Pyomo) and then connect the `FlowsheetBlock` (which comes from IDAES) to `m`. We ensure `dynamic=False` since this is a steady-state problem. This creates our overall model and adds the flowsheet capabilities that IDAES provides to the Pyomo model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -91,20 +111,29 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.521103Z", + "start_time": "2025-06-06T16:45:49.517229Z" + } + }, "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 3 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ - "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block.\n", + "At this point, we have a single Pyomo model that contains an (almost) empty flowsheet block. Lets use the `m.pprint()` to investigate the current contents of the model.\n", "\n", "
\n", "Inline Exercise:\n", @@ -113,41 +142,64 @@ ] }, { - "cell_type": "code", - "execution_count": 3, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.531374Z", + "start_time": "2025-06-06T16:45:49.527521Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: call pprint on the model", "outputs": [], - "source": [ - "# Todo: call pprint on the model" - ] + "execution_count": 4 }, { - "cell_type": "code", - "execution_count": 4, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.577500Z", + "start_time": "2025-06-06T16:45:49.572256Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: call pprint on the model\n", "m.pprint()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Block Declarations\n", + " fs : Size=1, Index=None, Active=True\n", + " 1 Set Declarations\n", + " _time : Size=1, Index=None, Ordered=Insertion\n", + " Key : Dimen : Domain : Size : Members\n", + " None : 1 : Any : 1 : {0.0,}\n", + "\n", + " 1 Declarations: _time\n", + "\n", + "1 Declarations: fs\n" + ] + } + ], + "execution_count": 5 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Define Properties\n", + "### 2.1 Define Properties\n", "\n", "We need to define the property package for our flowsheet. In this example, we will be using the ideal property package that is available as part of the IDAES framework. This property package supports ideal gas - ideal liquid, ideal gas - NRTL, and ideal gas - Wilson models for VLE. More details on this property package can be found at: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/property_models/activity_coefficient.html\n", "\n", - "IDAES also supports creation of your own property packages that allow for specification of the fluid using any set of valid state variables (e.g., component molar flows vs overall flow and mole fractions). This flexibility is designed to support advanced modeling needs that may rely on specific formulations. To learn about creating your own property package, please consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/components/property_package/index.html and look at examples within IDAES\n", + "IDAES also supports creation of your own property packages that will be shown in a later module. More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/properties/custom/index.html\n", "\n", "For this workshop, we will import the BTX_activity_coeff_VLE property parameter block to be used in the flowsheet. This properties block will be passed to our unit model to define the appropriate state variables and equations for performing thermodynamic calculations.\n", "\n", @@ -158,38 +210,48 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.649106Z", + "start_time": "2025-06-06T16:45:49.626357Z" + } + }, "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], "source": [ "from idaes.models.properties.activity_coeff_models.BTX_activity_coeff_VLE import (\n", " BTXParameterBlock,\n", ")" - ] + ], + "outputs": [], + "execution_count": 6 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.669359Z", + "start_time": "2025-06-06T16:45:49.657658Z" + } + }, "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], "source": [ "m.fs.properties = BTXParameterBlock(\n", " valid_phase=(\"Liq\", \"Vap\"), activity_coeff_model=\"Ideal\", state_vars=\"FTPz\"\n", ")" - ] + ], + "outputs": [], + "execution_count": 7 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Adding Flash Unit\n", + "### 2.2 Adding Flash Unit\n", "\n", - "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet. \n", + "Now that we have the flowsheet and the properties defined, we can create the flash unit and add it to the flowsheet.\n", "\n", "**The Unit Model Library within IDAES includes a large set of common unit operations (see the online documentation for details: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html**\n", "\n", - "IDAES also fully supports the development of customized unit models (which we will see in a later module).\n", + "IDAES also fully supports the development of customized unit models (which we will see in a later module). More details can be found here https://idaes-examples.readthedocs.io/en/latest/docs/unit_models/custom_unit_models/index.html.\n", "\n", "Some of the IDAES pre-written unit models:\n", "* Mixer / Splitter\n", @@ -200,7 +262,7 @@ "* Pressure changing equipment (compressors, expanders, pumps)\n", "* Feed and Product (source / sink) components\n", "\n", - "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash is the one we created earlier.\n", + "In this module, we will import the `Flash` unit model from `idaes.models.unit_models` and create an instance of the flash unit, attaching it to the flowsheet. Each IDAES unit model has several configurable options to customize the model behavior, but also includes defaults for these options. In this example, we will specify that the property package to be used with the Flash unit model is the one we created earlier by setting `property_package=m.fs.properties` within the `Flash` method.\n", "\n", "
\n", "Inline Exercise:\n", @@ -209,40 +271,183 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.749283Z", + "start_time": "2025-06-06T16:45:49.678730Z" + } + }, "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "source": "from idaes.models.unit_models import Flash", "outputs": [], - "source": [ - "from idaes.models.unit_models import Flash" - ] + "execution_count": 8 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.772441Z", + "start_time": "2025-06-06T16:45:49.758167Z" + } + }, "cell_type": "code", - "execution_count": 8, + "source": "m.fs.flash = Flash(property_package=m.fs.properties)", + "outputs": [], + "execution_count": 9 + }, + { "metadata": {}, + "cell_type": "markdown", + "source": "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.783706Z", + "start_time": "2025-06-06T16:45:49.781688Z" + }, + "tags": [ + "noauto" + ] + }, + "cell_type": "code", + "source": "m.pprint()", "outputs": [], + "execution_count": 10 + }, + { + "metadata": {}, + "cell_type": "markdown", "source": [ - "m.fs.flash = Flash(property_package=m.fs.properties)" + "## 3 Scaling the Model\n", + "\n", + "Now that the model is built, with properties set and the unit model created and added to the flowsheet, the next step is to scale the model. Ensuring that a model is well scaled is important for increasing the efficiency and reliability of solvers, and users should consider model scaling as an integral part of the modeling process. IDAES provides a number of tool for assisting users with scaling their models, and details on these can be found at https://idaes-pse.readthedocs.io/en/stable/reference_guides/scaling/scaling.html#scaling-toolbox\n", + "\n", + "There are currently two primary methods in scaling the model: manual scaling of each relevant component, or utilizing the AutoScaler Class. The more careful and risk-free method of manually scaling each component is the recommended method for maximum control and assurance that the model will be well-scaled. This comes with the drawback of being more meticulous while the AutoScaler is much simpler to use since it scaled the whole model all at once, it is less precise by lacking direct control over the scaling factor for each component and relying on scaling factors to be estimated. Both methods will be shown below" ] }, { + "metadata": {}, "cell_type": "markdown", + "source": [ + "### 3.1 Manual Scaling\n", + "The `set_scaling_factor` function is imported from `idaes.core.scaling.util` and is called with and used on each relevant component that needs to be well scaled. The component is the first argument and its scaling factor is the second argument.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `set_scaling_factor` and set the scaling factor for both temperature and pressure\n", + "
\n", + "\n", + "Both `temperature` and `pressure` can be found at `m.fs.flash.inlet`." + ] + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.795252Z", + "start_time": "2025-06-06T16:45:49.792075Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.util import set_scaling_factor", + "outputs": [], + "execution_count": 11 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.809330Z", + "start_time": "2025-06-06T16:45:49.806174Z" + } + }, + "cell_type": "code", + "source": [ + "set_scaling_factor(m.fs.flash.inlet.temperature, 300)\n", + "set_scaling_factor(m.fs.flash.inlet.pressure, 1e6)" + ], + "outputs": [], + "execution_count": 12 + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "At this point, we have created a flowsheet and a properties block. We have also created a flash unit and added it to the flowsheet. Under the hood, IDAES has created the required state variables and model equations. Everything is open. You can see these variables and equations by calling the Pyomo method `pprint` on the model, flowsheet, or flash tank objects. Note that this output is very exhaustive, and is not intended to provide any summary information about the model, but rather a complete picture of all of the variables and equations in the model." + "### 3.2 Scaling with AutoScaler\n", + "The `AutoScaler` class is imported from `idaes.core.scaling.autoscaling` and an instance of the class is created. This instance contains the method `scale_model` which is used to scale the whole model at once. This can be a useful option but is generally more risky than manually scaling the model components since it has less direct control and specification.\n", + "\n", + "
\n", + "Inline Exercise:\n", + "Execute the following two cells to import the `AutoScaler` class and create an autoscaler instance that scaled the whole model at once\n", + "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:49.826276Z", + "start_time": "2025-06-06T16:45:49.823030Z" + } + }, + "cell_type": "code", + "source": "from idaes.core.scaling.autoscaling import AutoScaler", + "outputs": [], + "execution_count": 13 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.217776Z", + "start_time": "2025-06-06T16:45:49.836920Z" + } + }, + "cell_type": "code", + "source": [ + "autoscaler = AutoScaler()\n", + "autoscaler.scale_model(m)" + ], + "outputs": [], + "execution_count": 14 + }, + { + "metadata": {}, "cell_type": "markdown", + "source": "" + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "## Set Operating Conditions\n", + "## 4 Set Operating Conditions\n", + "\n", + "Now that we have created our unit model and scaled it, we can specify the necessary operating conditions. The inlet specifications for this flash tank are:\n", "\n", - "Now that we have created our unit model, we can specify the necessary operating conditions. It is often very useful to determine the degrees of freedom before we specify any conditions.\n", + "Inlet Specifications:\n", + "* Mole fraction (Benzene) = 0.5\n", + "* Mole fraction (Toluene) = 0.5\n", + "* Pressure = 101325 Pa\n", + "* Temperature = 368 K\n", + "\n", + "\n" + ] + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "### 4.1 Degrees of Freedom\n", "\n", - "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n", + "It is often very useful to first determine the degrees of freedom before we specify any conditions.\n", "\n", + "The `idaes.core.util.model_statistics` package has a function `degrees_of_freedom`. To see how to use this function, we can make use of the Python function `help(func)`. This function prints the appropriate documentation string for the function.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Import the degrees_of_freedom function and print the help for the function by calling the Python help function.\n", @@ -250,41 +455,71 @@ ] }, { - "cell_type": "code", - "execution_count": 9, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.224457Z", + "start_time": "2025-06-06T16:45:50.221905Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function" - ] + ], + "outputs": [], + "execution_count": 15 }, { - "cell_type": "code", - "execution_count": 10, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.240605Z", + "start_time": "2025-06-06T16:45:50.237594Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: import the degrees_of_freedom function from the idaes.core.util.model_statistics package\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Todo: Call the python help on the degrees_of_freedom function\n", "help(degrees_of_freedom)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Help on function degrees_of_freedom in module idaes.core.util.model_statistics:\n", + "\n", + "degrees_of_freedom(block)\n", + " Method to return the degrees of freedom of a model.\n", + "\n", + " Args:\n", + " block : model to be studied\n", + "\n", + " Returns:\n", + " Number of degrees of freedom in block.\n", + "\n" + ] + } + ], + "execution_count": 16 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -293,36 +528,52 @@ ] }, { - "cell_type": "code", - "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.271361Z", + "start_time": "2025-06-06T16:45:50.268763Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: print the degrees of freedom for your model", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 17 }, { - "cell_type": "code", - "execution_count": 12, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.297399Z", + "start_time": "2025-06-06T16:45:50.291352Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 7\n" + ] + } + ], + "execution_count": 18 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ + "### 4.2 Specify Inlet Conditions\n", + "\n", "To satisfy our degrees of freedom, we will first specify the inlet conditions. We can specify these values through the `inlet` port of the flash unit.\n", "\n", "**To see the list of naming conventions for variables within the IDAES framework, consult the online documentation at: https://idaes-pse.readthedocs.io/en/stable/explanations/conventions.html#standard-naming-format**\n", @@ -339,7 +590,7 @@ "\n", "
\n", "Note:\n", - "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a timestep. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single timestep in the model.\n", + "The \"0\" in the indexing of the component mole fraction is present because IDAES models support both dynamic and steady state simulation, and the \"0\" refers to a time point. Dynamic modeling is beyond the scope of this workshop. Since we are performing steady state modeling, there is only a single time point in the model.\n", "
\n", "\n", "In the next cell, we will specify the inlet conditions. To satisfy the remaining degrees of freedom, we will make two additional specifications on the flash tank itself. The names of the key variables within the Flash unit model can also be found in the online documentation: https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/flash.html#variables.\n", @@ -359,7 +610,17 @@ "* inlet mole fraction (toluene) = 0.5 (`mole_frac_comp[0, \"toluene\"]`)\n", "* The heat duty on the flash set to 0 (`heat_duty`)\n", "* The pressure drop across the flash tank set to 0 (`deltaP`)\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Write the code below to specify the inlet conditions and unit specifications described above\n", @@ -367,30 +628,36 @@ ] }, { - "cell_type": "code", - "execution_count": 14, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.360852Z", + "start_time": "2025-06-06T16:45:50.357341Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "\n", "\n", "# Todo: Add 2 flash unit specifications given above" - ] + ], + "outputs": [], + "execution_count": 20 }, { - "cell_type": "code", - "execution_count": 15, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.396800Z", + "start_time": "2025-06-06T16:45:50.392314Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: Add inlet specifications given above\n", "m.fs.flash.inlet.flow_mol.fix(1)\n", @@ -402,11 +669,25 @@ "# Todo: Add 2 flash unit specifications given above\n", "m.fs.flash.heat_duty.fix(0)\n", "m.fs.flash.deltaP.fix(0)" + ], + "outputs": [], + "execution_count": 21 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": [ + "Now that all the inlets have been specified, we can check the degrees of freedom again to ensure the system is square and has a degree of freedom of 0.\n", + "\n" ] }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -415,79 +696,147 @@ ] }, { - "cell_type": "code", - "execution_count": 16, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", "outputs": [], - "source": [ - "# Todo: print the degrees of freedom for your model" - ] + "execution_count": 22, + "source": "# Todo: print the degrees of freedom for your model" }, { - "cell_type": "code", - "execution_count": 17, "metadata": { "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Degrees of Freedom = 0\n" + ] + } + ], + "execution_count": 23, "source": [ "# Todo: print the degrees of freedom for your model\n", "print(\"Degrees of Freedom =\", degrees_of_freedom(m))" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Initializing the Model\n", + "## 5 Initializing the Model\n", "\n", - "IDAES includes pre-written initialization routines for all unit models. You can call this initialize method on the units. In the next module, we will demonstrate the use of a sequential modular solve cycle to initialize flowsheets.\n", + "Now that all building steps are complete, the last step before solving the model is to initialize the model, or prepping the solve by giving it a good starting point. This is essentially giving the solver an initial guess for the iterative solver to reach convergence and is essential for both a fast and accurate solution. In IDAES, the current standard for initializing the model is by utilizing initializer instances. These initializer instances contain the initialize method that can be applied to any model type. For more information on initializing in IDAES, visit https://idaes-pse.readthedocs.io/en/stable/reference_guides/initialization/index.html.
\n", "\n", + "For this tutorial, we will import the initializer class `BlockTriangularizationInitializer` class from the `default_initializer` method from the flash unit model. This is often the simplest way to obtain a compatible initializer for each unit model, but you can also directly important any initializer needed from this source `idaes.core.initialization`. Each initializer instance contains the `initialize()` method that requires an argument to be initialized and in this case its the flash unit model.\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", - "Call the initialize method on the flash unit to initialize the model.\n", + "Define the initializer instance, and initialize the flash unit model\n", "
" ] }, { - "cell_type": "code", - "execution_count": 19, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:45:50.499945Z", + "start_time": "2025-06-06T16:45:50.497439Z" + }, "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: initialize the flash unit", "outputs": [], - "source": [ - "# Todo: initialize the flash unit" - ] + "execution_count": 25 }, { - "cell_type": "code", - "execution_count": 20, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T16:51:40.247234Z", + "start_time": "2025-06-06T16:51:39.730044Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: initialize the flash unit\n", - "m.fs.flash.initialize(outlvl=idaeslog.INFO)" - ] + "FlashInitializer = m.fs.flash.default_initializer()\n", + "FlashInitializer.initialize(m.fs.flash)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:39 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 10:51:40 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 33 }, { + "metadata": {}, "cell_type": "markdown", + "source": "Another option for initializing is utilizing the default initializer that is attached to the unit model. Each unit model as a default initializer that is hypothetically the most compatible. It can be called with `m.fs.flash.initialize()`. While this is an option, it is generally preferred to import an initializer object and initialize the model with that to ensure more control over the initialization." + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ - "Now that the model has been defined and initialized, we can solve the model.\n", + "## 6 Solving the Model\n", "\n", + "Now that the model has been defined and initialized, we can solve the model.\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using the notation described in the previous model, create an instance of the \"ipopt\" solver and use it to solve the model. Set the tee option to True to see the log output.\n", @@ -495,42 +844,120 @@ ] }, { - "cell_type": "code", - "execution_count": 21, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.219172Z", + "start_time": "2025-06-06T17:04:32.216161Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "\n", "# Todo: solve the model" - ] + ], + "outputs": [], + "execution_count": 36 }, { - "cell_type": "code", - "execution_count": 22, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:32.439966Z", + "start_time": "2025-06-06T17:04:32.396984Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: create the ipopt solver\n", "solver = SolverFactory(\"ipopt\")\n", "\n", "# Todo: solve the model\n", "status = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 135\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 41\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 6.22e-05 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e-11 1.00e-02 -1.0 6.22e-05 - 9.90e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 1\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 2.0417014662014577e-12 1.4551915228366852e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 2\n", + "Number of objective gradient evaluations = 2\n", + "Number of equality constraint evaluations = 2\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 2\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 1\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 37 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Viewing the Results\n", + "## 7 Viewing the Results\n", "\n", "Once a model is solved, the values returned by the solver are loaded into the model object itself. We can access the value of any variable in the model with the `value` function. For example:\n", "```python\n", @@ -550,10 +977,13 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:35.556815Z", + "start_time": "2025-06-06T17:04:35.551070Z" + } + }, "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], "source": [ "# Print the pressure of the flash vapor outlet\n", "print(\"Pressure =\", value(m.fs.flash.vap_outlet.pressure[0]))\n", @@ -563,34 +993,89 @@ "# Call display on vap_outlet and liq_outlet of the flash\n", "m.fs.flash.vap_outlet.display()\n", "m.fs.flash.liq_outlet.display()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Pressure = 101325.0\n", + "\n", + "Output from display:\n", + "vap_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.3961181748774193}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.633976648508129, (0.0, 'toluene'): 0.366023351491871}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n", + "liq_outlet : Size=1\n", + " Key : Name : Value\n", + " None : flow_mol : {0.0: 0.6038818251225807}\n", + " : mole_frac_comp : {(0.0, 'benzene'): 0.41211759772293044, (0.0, 'toluene'): 0.5878824022770694}\n", + " : pressure : {0.0: 101325.0}\n", + " : temperature : {0.0: 368.0}\n" + ] + } + ], + "execution_count": 39 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "The output from `display` is quite exhaustive and not really intended to provide quick summary information. Because Pyomo is built on Python, there are opportunities to format the output any way we like. Most IDAES models have a `report` method which provides a summary of the results for the model.\n", "\n", "
\n", "Inline Exercise:\n", - "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports. \n", + "Execute the cell below which uses the function above to print a summary of the key variables in the flash model, including the inlet, the vapor, and the liquid ports.\n", "
" ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:38.727731Z", + "start_time": "2025-06-06T17:04:38.712131Z" + } + }, "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "m.fs.flash.report()" - ] + "source": "m.fs.flash.report()", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 0.0000 : watt : True : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.39612 0.60388 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.63398 0.41212 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.36602 0.58788 \n", + " temperature kelvin 368.00 368.00 368.00 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 40 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Studying Purity as a Function of Heat Duty\n", + "## Exercise: Studying Purity as a Function of Heat Duty\n", "\n", "Since the entire modeling framework is built upon Python, it includes a complete programming environment for whatever analysis we may want to perform. In this next exercise, we will make use of what we learned in this and the previous module to generate a figure showing some output variables as a function of the heat duty in the flash tank.\n", "\n", @@ -602,22 +1087,35 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:04:43.426680Z", + "start_time": "2025-06-06T17:04:43.423025Z" + } + }, "cell_type": "code", - "execution_count": 27, - "metadata": {}, + "source": "import matplotlib.pyplot as plt", "outputs": [], - "source": [ - "import matplotlib.pyplot as plt" - ] + "execution_count": 42 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Exercise specifications:\n", "* Generate a figure showing the flash tank heat duty (`m.fs.flash.heat_duty[0]`) vs. the vapor flowrate (`m.fs.flash.vap_outlet.flow_mol[0]`)\n", "* Specify the heat duty from -17000 to 25000 over 50 steps\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Using what you have learned so far, fill in the missing code below to generate the figure specified above. (Hint: import numpy and use the linspace function from the previous module)\n", @@ -625,14 +1123,12 @@ ] }, { - "cell_type": "code", - "execution_count": 29, "metadata": { "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -645,22 +1141,22 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "UnitModelInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "\n", " # fix the heat duty\n", " m.fs.flash.heat_duty.fix(duty)\n", - " \n", + "\n", " # append the value of the duty to the Q list\n", " Q.append(duty)\n", - " \n", + "\n", " # print the current simulation\n", " print(\"Simulating with Q = \", value(m.fs.flash.heat_duty[0]))\n", "\n", " # Solve the model\n", " status = solver.solve(m)\n", - " \n", + "\n", " # append the value for vapor fraction if the solve was successful\n", " if solve_successful(status):\n", " V.append(value(m.fs.flash.vap_outlet.flow_mol[0]))\n", @@ -668,7 +1164,7 @@ " else:\n", " V.append(0.0)\n", " print('... solve failed.')\n", - " \n", + "\n", "# Create and show the figure\n", "plt.figure(\"Vapor Fraction\")\n", "plt.plot(Q, V)\n", @@ -676,18 +1172,21 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [], + "execution_count": null }, { - "cell_type": "code", - "execution_count": 30, "metadata": { - "scrolled": true, + "ExecuteTime": { + "end_time": "2025-06-06T17:04:48.800601Z", + "start_time": "2025-06-06T17:04:46.438264Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# import the solve_successful checking function from workshop tools\n", "from idaes_examples.mod.tut.workshoptools import solve_successful\n", @@ -700,7 +1199,7 @@ "V = []\n", "\n", "# re-initialize model\n", - "m.fs.flash.initialize(outlvl=idaeslog.WARNING)\n", + "FlashInitializer.initialize(m.fs.flash)\n", "\n", "# Todo: Write the for loop specification using numpy's linspace\n", "for duty in np.linspace(-17000, 25000, 50):\n", @@ -731,11 +1230,244 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_in: Initialization Step 5 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 1 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 2 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 3 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 4 optimal - .\n", + "2025-06-06 11:04:46 [INFO] idaes.init.fs.flash.control_volume.properties_out: Initialization Step 5 optimal - .\n", + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAGwCAYAAABVdURTAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAATA1JREFUeJzt3QdYFNf+PvCXpYMUEQFFrKjYEARBNMYUW2K5KUZjRUSjSbwaNUUTozG5UWMSrzExlliwxh5NotfYjUYFxV6wK4oCYqMJLLv7f87xB39QVBaB2fJ+nmdkZ3Z2+bLDLq9nzpljodPpdCAiIiIyESqlCyAiIiIqTQw3REREZFIYboiIiMikMNwQERGRSWG4ISIiIpPCcENEREQmheGGiIiITIoVzIxWq8X169fh5OQECwsLpcshIiKiYhCX5UtLS0PVqlWhUj25bcbswo0INj4+PkqXQURERCVw9epVVKtW7Yn7mF24ES02eS+Os7Oz0uWYLbVajc2bN6N9+/awtrZWuhx6Ah4r48LjZTx4rPSTmpoqGyfy/o4/idmFm7xTUSLYMNwo+6Z2cHCQx4BvasPGY2VceLyMB49VyRSnSwk7FBMREZFJYbghIiIik8JwQ0RERCaF4YaIiIhMCsMNERERmRSGGyIiIjIpDDdERERkUhhuiIiIyKQw3BAREZFJYbghIiIik6JouPn777/RpUsXOcOnuJzyunXrnvqYnTt3olmzZrC1tYWvry+ioqLKpVYiIiIyDoqGm4yMDDRt2hQzZswo1v6XLl1Cp06d8OKLL+LIkSP44IMPMHDgQPz1119lXisREREZB0UnznzllVfkUlyzZs1CrVq18P3338v1Bg0aYM+ePfjvf/+LDh06lGGlRERE5etephpp2WoYIxsrFTyc7BT7/kY1K/i+ffvQtm3bQttEqBEtOI+TnZ0tl4JTpufNxioWUkbea89jYPh4rIwLj5fxH6vzyemYuesS/jx+A1odjFKgjwtWvhNaqs+pz++0UYWbxMREeHp6Ftom1kVguX//Puzt7R95zKRJkzBhwoRHtm/evFlONU/K2rJli9IlUDHxWBkXHi/jO1bXM4DNCSocuWUBHSzkNmsL40w3affuYuPGjaX6nJmZmaYZbkpizJgxGDlyZP66CEI+Pj5o3749nJ2dFa3NnIkELt7Q7dq1g7W1tdLl0BPwWBkXHi/jO1bejVtg9p54bDmdnH9fuwYeeP+F2mhUlX+nHj7zYnLhxsvLC0lJSYW2iXURUopqtRHEqCqxPEy86fnGVx6Pg/HgsTIuPF6G7+i1e5gTp8LJfQfluoUF8GqTKhj6oi8aVGGoeZg+v89GFW7CwsIeaeYSqVdsJyIiMgbxtzLx+foT2HX2phy0rLIAujStKkNNXU8npcszCYqGm/T0dJw/f77QUG8xxNvNzQ3Vq1eXp5QSEhKwaNEief+QIUPw008/4eOPP8aAAQOwfft2rFy5Ehs2bFDwpyAiIiqeU9dT0W9+DFLSs2GpskBQJQ3+06s16lVxVbo0k6LodW4OHjyIwMBAuQiib4y4PW7cOLl+48YNxMfH5+8vhoGLICNaa8T1ccSQ8Llz53IYOBERGbwDl2+jx5x9MtiI005/DW+F3r5a1HJ3VLo0k6Noy80LL7wAne7xPcGLuvqweMzhw4fLuDIiIqLSsz0uCe8uOYTsXC2a16yIueHN4WAFnFS6MBNlVH1uiIiIjM26wwkYteooNFodXvLzwIxezWBvY8lrEZUhhhsiIqIyEvXPJXzxxyl5+/VAb0zp5g9rS85ZXdYYboiIiEqZ6HIxbes5/LDtnFzv37ImxnVuCJUYGkVljuGGiIioFGm1Okz44yQW7rsi10e2q4d/v+QLC3EhGyoXDDdERESlRK3RYtTKo/j96HV5Ub4JXRuhX1hNpcsyOww3REREpeB+jgbvLY3FjjM3YaWywPfdm+JfAd5Kl2WWGG6IiIie0b37akRGHcDBK3dgZ63CzN5BeNHPQ+myzBbDDRER0TNITs2SVx2OS0yDs50V5vdvjuCabkqXZdYYboiIiJ5hnqg+86IRfzsT7hVssTgyhJNeGgCGGyIiohKIS0xFv3kxSE7Lho+bPZZEhqJGJU6lYAgYboiIiPQUe+UOIhbEIDUrF/U9nbAoMgSeznZKl0X/h+GGiIhID7vO3sSQxbG4r9agWXVXLOgfAhcHa6XLogIYboiIiIrpj6PXMXLlEag1OrSpVxkz+zSDgw3/lBoaHhEiIqJiWLL/Cj5ffwI6HdClaVV8/1ZT2FhxnihDxHBDRET0lHmiftp+Ht9vOSvX+7SojgldG8OS80QZLIYbIiKiJ8wT9Z8NpzH/n0tyXcwRJeaK4jxRho3hhoiIqAi5Gi0+XnMMaw8lyPXPOzdE5HO1lC6LioHhhoiI6CFZag2GLjuMraeT5OmnKW/6482gakqXRcXEcENERFRAapYagxYeRPSl27LD8IxezdCuoafSZZEeGG6IiIj+T0p6NsLnx+Dk9VRUsLXC3PBgtKhdSemySE8MN0RERACu3clE33kxuJSSgUqONlg4IASNvV2ULotKgOGGiIjM3rmkNBlsElOz4O1qLyfArF25gtJlUQkx3BARkVk7evUu+i+IwZ1MNepUdsSSgaGo4mKvdFn0DBhuiIjIbP1zPgWDFh1EZo4G/tVcEBURAjdHG6XLomfEcENERGZp04kbGPbrEeRotGjlWwmz+wbLTsRk/HgUiYjI7Kw4EI8xa49DqwM6NvLCDz0DYGtlqXRZVEoYboiIyKzM3nUBk/4XJ2/3CPbBxDeacJ4oE8NwQ0REZjMB5jebzmDWrgtyfXCb2hjd0Y/zRJkghhsiIjJ5Gq0OY9cdx68xV+X66Ff8MKRNHaXLojLCcENERCYtO1eDESuOYOPxRIizTxNfb4K3Q6orXRaVIYYbIiIyWRnZuRiyJBa7z6XAxlKFH94OwCtNqihdFpUxhhsiIjJJdzJyEBF1AEeu3oWDjSXm9A3Gc3XdlS6LygHDDRERmZzEe1noOy8a55LT4epgLS/OF+DjqnRZVE4YboiIyKSIiS/7zI1Gwt378HK2k/NE1fV0UrosKkcMN0REZDJOXr+H8PkxSEnPQS13RxlsqlV0ULosKmcMN0REZBJiLt1GZNQBpGXnomEVZywcEILKTrZKl0UKYLghIiKjtz0uCe8uOYTsXC1Carphbv9gONtZK10WKYThhoiIjNq6wwn4cNVR5Gp1eNnPAzN6N4OdNeeJMmcMN0REZLQW7r2M8b+flLdfD/TGlG7+sLZUKV0WKYzhhoiIjHKeqB+2ncO0refkev+WNTGuc0OoOAEmMdwQEZGx0Wp1+PLPU4jae1muj2hbD8Ne9uUEmJSP4YaIiIyGWqPFx6uP4bfDCXJ9QtdGCG9ZU+myyMAw3BARkVHIUmvw/tJD2BaXDCuVBb7v3hT/CvBWuiwyQAw3RERk8FKz1BgYdRAxl2/D1kqFmX2a4SU/T6XLIgPFcENERAbtZlq2vOrwqRupcLKzwvz+zdG8ppvSZZEBY7ghIiKDdfV2JvrNj5HzRblXsMXCAc3RqKqL0mWRgWO4ISIig3QuKQ1958UgMTUL1SraY0lkKGq6OypdFhkBhhsiIjI4R67eRf8FMbibqUZdjwpYHBkKLxc7pcsiI8FwQ0REBuWf8ykYtOggMnM0CPBxxYL+zVHR0UbpssiIMNwQEZHB2HTiBob9egQ5Gi2e83XH7L5BcLTlnyrSD39jiIjIIKw8cBWj1x6DVge80tgL094OgK0VJ8Ak/THcEBGR4ub8fQETN8bJ2z2CfTDxjSaw5DxRVEIMN0REpOgEmFP+OoOZOy/I9cFtamN0Rz/OE0XPhOGGiIgUodHqMHbdCfwaEy/XP+noh3dfqKN0WWQCGG6IiKjcZedqMHLFUWw4fgOikWbi603QM6S60mWRiWC4ISKicpWRnYshS2Kx+1wKrC0tMK1HIDr5V1G6LDIhDDdERFRu7mbmICLqAA7H34W9taUc6v18vcpKl0UmRqV0ATNmzEDNmjVhZ2eH0NBQxMTEPHH/adOmoX79+rC3t4ePjw9GjBiBrKyscquXiIhKJik1Cz1m75fBxsXeGksGhjLYkOmFmxUrVmDkyJEYP348Dh06hKZNm6JDhw5ITk4ucv9ly5Zh9OjRcv/Tp09j3rx58jk+/fTTcq+diIiK78qtDHSbtRdnktLg4WSLlYPDEFSjotJlkYlS9LTU1KlTMWjQIERERMj1WbNmYcOGDZg/f74MMQ/bu3cvWrVqhV69esl10eLTs2dPREdHP/Z7ZGdnyyVPamqq/KpWq+VCysh77XkMDB+PlXExxOMVl5iGAQtjcTM9B9Xd7LEgPAjV3ewMqkYlGOKxMmT6vE6KhZucnBzExsZizJgx+dtUKhXatm2Lffv2FfmYli1bYsmSJfLUVUhICC5evIiNGzeib9++j/0+kyZNwoQJEx7ZvnnzZjg4OJTST0MltWXLFqVLoGLisTIuhnK8LqUBs09b4r7GAlUddBhUKw0n9u/ECaULMyCGcqwMXWZmpuGHm5SUFGg0Gnh6ehbaLtbj4h5cpfJhosVGPO65556TF37Kzc3FkCFDnnhaSoQnceqrYMuN6KvTvn17ODs7l+JPRPomcPGGbteuHaytrZUuh56Ax8q4GNLx+vtcCmb9egRZGi2aVXfFnD6Bsq8NGd6xMgZ5Z15MbrTUzp07MXHiRPz888+y8/H58+cxfPhwfPXVV/j888+LfIytra1cHiZ+kfjLpDweB+PBY2VclD5efxy9jpErj0Ct0aFNvcqY2acZHGyM6k+O2RwrY6HPa6TYb5q7uzssLS2RlJRUaLtY9/LyKvIxIsCIU1ADBw6U602aNEFGRgbeeecdfPbZZ/K0FhERKWtp9BV55WGdDujsXwVTuwfAxoqfz1R+FPtts7GxQVBQELZt25a/TavVyvWwsLDHnm97OMCIgCSI01RERKQc8Tk8Y8d5fPbbg2DTO7Q6fng7kMGGyp2ibYSiL0x4eDiCg4NlB2FxDRvREpM3eqpfv37w9vaWnYKFLl26yBFWgYGB+aelRGuO2J4XcoiISJlgM3Hjafyy+5JcH/qiL0a1r8cJMMn8wk2PHj1w8+ZNjBs3DomJiQgICMCmTZvyOxnHx8cXaqkZO3asfKOIrwkJCahcubIMNl9//bWCPwURkXnL1Wjx6W/HsfLgNbk+tlMDDGxdW+myyIwp3rtr6NChcnlcB+KCrKys5AX8xEJERMrLUmswfPlh/HUyCSoLYPKb/uge7KN0WWTmFA83RERknNKzczF48UH8c/4WbCxVmN4zEB0bFz0ghKg8MdwQEZHe7mTkoH/UARy9eheONpaY0y8YrXzdlS6LSGK4ISIivSTey0LfedE4l5yOig7WiIoIQVMfV6XLIsrHcENERMV2KSUDfeZGI+HufXg522FxZAjqejopXRZRIQw3RERULKeup6Lf/BikpGejlrujDDbVKnKOPjI8DDdERPRUBy/fRkTUAaRl5aJhFWcsHBCCyk6PTm1DZAgYboiI6Il2nEnGu0tikaXWonnNipjXvzmc7TgXEhkuhhsiInqs38UEmCuOIFerw4v1K+Pn3kGwt+EV4cmwMdwQEVGRluy/gs/XP5gn6l8BVfHdW01hbcl5osjwMdwQEdEj80T9vPMCvv3rjFzvF1YDX3RpBJW4BDGREWC4ISKix06AOewlX4xoxwkwybgw3BARUZETYH7euSEin6uldFlEemO4ISKiQhNgWqos8M2b/ugWVE3psohKhOGGiMjMZWTn4p0CE2D+2CsQHRpxAkwyXgw3RERm7OEJMH/pF4yWnACTjBzDDRGRmeIEmGSqGG6IiMzQZTEB5rxoXLvzYALMJQND4OvBCTDJNDDcEBGZGU6ASaaO4YaIyIxwAkwyBww3RERmYueZZAwpMAHm3PDmcLHnBJhkehhuiIjMwB9Hr2PE/02A+UL9ypjJCTDJhDHcEBGZuKXRVzB23YMJMLs2fTABpo0VJ8Ak08VwQ0RkwvNEzdx1AVM2PZgAs0+L6viya2NOgEkmj+GGiMhEg82k/8Vhzt8X5frQF30xqj0nwCTzwHBDRGRitDrgs/WnsCo2Qa6P7dQAA1vXVrosonLDcENEZEKyc7WIOqvC0dsJEGefJr/pj+7BPkqXRVSuGG6IiExoAszBSw7j6G0VrC0t8GPPZujYmBNgkvlhuCEiMgF3M3PQf8EBHLl6FzYqHX7pG4Q2fgw2ZJ4YboiIjFxSahb6zYvBmaQ0uNhbYUCdLLSsU0npsogUwwsdEBEZsSu3MtBt1l4ZbDydbfFrZAhqcv5LMnNsuSEiMlJxianoOy8GN9OyUaOSA5ZEhsLLyRrnlC6MSGEMN0RERij2yh0MiDqAe/fV8PNywqIBIfBwtoNarVa6NCLFMdwQERmZv8/exODFsbiv1qBZdVcs6B8CFwdOgEmUh+GGiMiIbDx+A8OXH4Zao0Pruu6Y3TcIDjb8KCcqiO8IIiIjseJAPMasPS6vQNypSRVM7dEUtlac2ZuoROHm2LFj0FfDhg1hZcXsRERUGub8fQETN8bJ228398HXrzeBJSfAJCpSsdJHQECAnGxNTMRWHCqVCmfPnkXt2pzLhIjoWYjP3W//OoOfd16Q64Ofr43Rr/hxAkyiJyh200p0dDQqV65crDdi48aNi/u0RET0GBqtDuPWn8DS6Hi5/klHP7z7Qh2lyyIyjXDTpk0b+Pr6wtXVtVhP+vzzz8Pe3v5ZayMiMls5uVqMXHkEfx67AdFI8/VrTdArtLrSZRGZTrjZsWOHXk+6cePGktZDRGT27udo8O7SWOw8c1NOgDm1ewC6NK2qdFlE5jH9wj///IPs7OzSq4aIyMyJi/L1nRctg42dtQq/9AtmsCEqz3DzyiuvICEh4VmegoiI/o+YRqHnnP04eOUOnOyssDgyFC/U91C6LCKj80xjtYs7eoqIiJ7s2p1MOU/UpZQMuFewwcIBIWhU1UXpsoiMEi9EQ0SksPPJ6fJU1I17WfB2tcfiyBDUrlxB6bKIzDPczJ49G56enqVXDRGRmTl+7R7CF8TgdkYO6lR2xJKBoajiwtGmRIqFm169ej3TNyciMmf7LtzCoEUHkZ6diybeLvJUlJujjdJlEZlHh+I33ngDqampxX7S3r17Izk5+VnqIiIyaVtPJckWGxFsQmu5YdmgUAYbovJsuVm/fj1u3rxZ7E7Gf/zxB7766it4eLCXPxHRw347fA0frjomr0DctoEHfurVDHbWnACTqFzDjQgs9erVK7VvSkRkrhbuvYzxv5+Ut18P9MaUbv6wtnymq3IQUXlcoVjw9vbW+zFERKZK/Cfxx+3nMXXLWbkeHlYD47s0goozexMpN7cUERGVjFarw9cbT2PenktyffjLdfFB27qc2ZuojPA6N0REZShXo8XotcexOvaaXB/XuSEGPFdL6bKITBrDDRFRGcnO1WD4r0ew6WQixNmnb970x1vBPkqXRWTyGG6IiMpARnYu3ll8EP+cvwUbSxV+7BWIDo28lC6LyCww3BARlbK7mTnov+AAjly9CwcbSzmzdytfd6XLIjIbDDdERKUoOTVLToB5JikNrg7WiIoIQYCPq9JlEZkVvS+ukJSUhL59+6Jq1aqwsrKCpaVloUVfM2bMQM2aNWFnZ4fQ0FDExMQ8cf+7d+/i/fffR5UqVWBrayuvv7Nx40a9vy8RUWmLv5WJbrP2yWDj4WSLFe+EMdgQGUPLTf/+/REfH4/PP/9cBoxnGcq4YsUKjBw5ErNmzZLBZtq0aejQoQPOnDlT5NWNc3Jy0K5dO3nf6tWr5bV0rly5AldXfngQkbLOJKbJmb2T07JR3c0BSweGwsfNQemyiMyS3uFmz5492L17NwICAp75m0+dOhWDBg1CRESEXBchZ8OGDZg/fz5Gjx79yP5i++3bt7F3715YW1vLbaLV50mys7Plkidvjiy1Wi0XUkbea89jYPh4rJ5O9K0ZuPgQ7t3PRT2PCljQPwgeTtaKvGY8XsaDx0o/+rxOFjpx2Uw9NGzYEEuXLkVgYCCehWiFcXBwkC0wr732Wv728PBweepJzGf1sFdffRVubm7yceL+ypUry5nJP/nkk8eeEvviiy8wYcKER7YvW7ZMPg8R0bM4c88Cc+NUyNFaoGYFHd7x08Dxwf+9iKgUZWZmyr/59+7dg7Ozc+m23IhTR6JVZfbs2U9tNXmSlJQUaDQaeHp6Ftou1uPi4op8zMWLF7F9+3Y567joZ3P+/Hm89957Ms2NHz++yMeMGTNGnvoq2HLj4+OD9u3bP/XFobIjjtmWLVvkaca8VjgyTDxWj7flVDJ+WXkUaq0OLeu44eeeAXC0VXacBo+X8eCx0k/emZfi0Ptd2KNHD5me6tSpI1s+Hj4g4rRRWdFqtbK/zZw5c2RLTVBQEBISEvDtt98+NtyITsdieZiom79MyuNxMB48VoWJKw5/vPootDqgYyMv/NAzALZWhjOzN4+X8eCxKh59XqMStdyUBnd3dxlQxOirgsS6l1fRF7oSHZjFD1fwFFSDBg2QmJgoT3PZ2NiUSm1ERE+y4J9LmPDHKXn7raBqmPRGE1hxZm8ig6F3uBF9YkqDCCKi5WXbtm35fW5Ey4xYHzp0aJGPadWqlewrI/ZTqR58kJw9e1aGHgYbIiprooviD9vOYdrWc3I98rla+OzVBpzZm8jAlOjksOgrs27dOpw+fVquN2rUCF27dtX7OjeiL4wIS8HBwQgJCZGtQhkZGfmjp/r16yeHe0+aNEmuv/vuu/jpp58wfPhw/Pvf/8a5c+cwceJEDBs2rCQ/BhGRXjN7f/nnKUTtvSzXR7Wrh6Ev+XJmbyJTCDeiE68YtST6utSvX19uE+FDdNIVw7hFXxx9+u/cvHkT48aNk6eWxPDyTZs25XcyFtfTyWuhEcT3+OuvvzBixAj4+/vL4COCjhgtRURUljN7f7LmONYcejCz94SujRDesuQDKojIwMKNaCURAWb//v1yWLZw69Yt9OnTR94nAo4+xCmox52G2rlz5yPbwsLC5PcmIioPWWoNhv16GJtPJcFSZYFvu/njjWbVlC6LiEoz3OzatatQsBEqVaqEyZMnyz4xRESmIj07F4PzZva2UmFGr2Zo17Dw5SuIyATCjRhWnZaW9sj29PR0duolIpOa2Tt8wQEcvXoXjmJm7/BgtKzDmb2JjIHeYxc7d+6Md955B9HR0XLkgFhES86QIUNkp2IiImOXlJqF7rP3yWAjZvZeNqgFgw2RKYeb6dOnyz43ou+LmMlbLOJ0lK+vL3744YeyqZKIqBxn9n5r1j6cTUqHp7MtVg4OQ1PO7E1k2qelxAzcYl4nMQw7b5oEcSE9EW6IiIwZZ/YmMg0lngSlbt26ciEiMgWH4++g/4IDuHdfDT8vJywaEAIPZzulyyKisgo34mJ7X331FRwdHQtNQlmUqVOnlqQOIiLF7D2fgoGLDiIzR4PA6q5Y0L85XB04QILIpMPN4cOH5eylebeJiEzFXycT8e9lh5Gj0eI5X3fM7huk+MzeRPRsivUO3rFjR5G3iYiM2Roxs/eaY9BodejQyBPTewYa1MzeRFROo6UGDBhQ5HVuxJxQ4j4iImMQ9c8ljFp1VAabbkHV5AX6GGyIzDTcLFy4EPfv339ku9i2aNGi0qqLiKjsZvbeeg5f/HFKrg9oVQtT3vSHlaXeH4dEZKCKfWI5NTU1/6J9ouVGXN+m4CzhGzduhIeHR1nVSURUKjN7/2fDacz/55JcH9G2Hoa9zJm9icw23Ijr24gPALHUq1fvkfvF9gkTJpR2fUREpTaz9+i1x7E69sHM3uO7NEREq1pKl0VESoYb0ZFYtNq89NJLWLNmTaGJM8WcUjVq1EDVqlXLokYiomeSnavB8F+PYNPJRKgsgG+7NcWbQZzZmwjmHm7atGkjv166dAnVq1dnMy4RGYWM7FwMWRKL3edSYGOpkiOiOjb2UrosIipDeveg2759O1avXv3I9lWrVsnOxkREhuJeplpOpyCCjYONJeb3b85gQ2QG9A43kyZNgrv7o7Pjis7EEydOLK26iIieSXJaFnrM2YdD8XfhYm+NJQND8VxdzuxNZA70vgxnfHw8atV6tBOe6HMj7iMiUtrV25myxebyrUxUdrLF4sgQ+Hk5K10WERlqy41ooTl27Ngj248ePYpKlSqVVl1ERCVyPjkNb83aJ4ONj5s9Vg8JY7AhMjN6t9z07NkTw4YNg5OTE55//nm5bdeuXRg+fDjefvvtsqiRiKhYjl+7h/AFMbidkYO6HhWwODIUXi6c2ZvI3OgdbsTs4JcvX8bLL78MK6sHD9dqtejXrx/73BCRYqIv3kLkwoNIz86FfzUXREWEwM2RM3sTmSO9w424ps2KFStkyBGnouzt7dGkSRPZ54aISAnb45Lw7pJDyM7VokVtN/zSLxhOdtZKl0VExhJu8oirFBd1pWIiovL0+9HrGLniCHK1OrRt4IGfejWDnTUnwCQyZyUKN9euXcPvv/8uR0fl5OQUum/q1KmlVRsR0RMtjb6CsetOQKcDXguoim/fagprToBJZPb0Djfbtm1D165dUbt2bcTFxaFx48ayD46YmqFZs2ZlUyUR0UNm7bqAyf+Lk7f7tqiBCV0bQSXmViAis6f3f3HGjBmDDz/8EMePH5czg4t5pq5evSqnZ3jrrbfKpkoiov8j/iP1zaa4/GDz/ot18OW/GGyI6BnCzenTp+XIKEGMlrp//z4qVKiAL7/8Et98842+T0dEVGxarU6ehpq584JcH/OKHz7q4Me57ojo2cKNo6Njfj+bKlWq4MKFBx8yQkpKir5PR0RULGqNFiNWHsHS6HiILDPpjSYY3KaO0mURkSn0uWnRogX27NmDBg0a4NVXX8WoUaPkKaq1a9fK+4iISluWWoP3lx7CtrhkWKks8N8eAejStKrSZRGRqYQbMRoqPT1d3p4wYYK8La57U7duXY6UIqJSl5alxsCFBxF96TZsrVSY1ScIL/p5KF0WEZlKuNFoNHIYuL+/f/4pqlmzZpVVbURk5sQ0Cv0XxODYtXuoYGuFeeHBCK3NOeyIqBT73FhaWqJ9+/a4c+eOPg8jItJb4r0sdJ+9TwYbMY3Cr4NaMNgQUdl0KBbXtbl48aK+DyMiKrYrtzLQbdZenE9Oh5ezHVYODkOTai5Kl0VEphpu/vOf/8jr3Pz555+4ceMGUlNTCy1ERM/iTGIaus3ah2t37qNmJQesGhIGX48KSpdFRKbcoViMkBLEVYoLXltCXFhLrIt+OUREJXE4/g76LziAe/fV8PNywqLIEHg42SldFhGZerjZsWNH2VRCRGZt7/kUDFx0EJk5GgRWd0VU/xC4OHBmbyIqw3Ajrko8Y8YMOc2CcPToUTRs2BDW1vzwIaJns/lkIob+ehg5uVq08q2EOX2D4Whbonl9iYiK3+dm6dKlcqqFPK1bt5ZzShERPYvfDl/Du0sPyWDTvqEn5oU3Z7AhomdS7E8Q0afmSetERPpavO8yPl9/Ut5+o5k3przpDytLvcc5EBEVwv8eEVG5E/85+nnnBXz71xm53r9lTYzr3JAzexNR+YebU6dOITExMf/DKS4uLn8qhjx5Vy8mIiqK+OyY/L84zP77wfWyhr3kixHt6nFmbyJSJty8/PLLhU5Hde7cWX4VH0ocCk5ET6PR6jB23Qn8GhMv18d2aoCBrWsrXRYRmWu4uXTpUtlWQkQmTa3RYsSKI/jz2A2Is0+T3miCHs2rK10WEZlzuKlRo0bZVkJEJitLrcF7Sw9he1wyrC0tMK1HIDr5V1G6LCIyUexQTERlKi1LjciFBxFz6TbsrFWY1ScIL9T3ULosIjJhDDdEVGZuZ+QgfH4Mjifcg5OtFeb1b46QWm5Kl0VEJo7hhojKROK9LPSZFy1n9nZztMGiASFo7M2ZvYmo7Ol1tSwxIio+Ph5ZWVllVxERGb0rtzLQbdZeGWy8nO2wcnAYgw0RGW648fX15bQLRPRYZxLT0G3WPly7cx81Kzlg1ZAw+HpUULosIjIjeoUblUqFunXr4tatW2VXEREZrSNX76L77H24mZYNPy8nrBwSBh83B6XLIiIzo/ckLpMnT8ZHH32EEydOlE1FRGSU9l5IQe9f9uPefTUCq7ti+Tst4OFkp3RZRGSG9O5Q3K9fP2RmZqJp06awsbGBvb19oftv375dmvURkRHYeioJ7y17MLN3K99KmNM3mDN7E5Fi9P70mTZtWtlUQkRGaf2RBIxceVROrdCuoSd+7BkIO2tLpcsiIjOmd7gJDw8vm0qIyOgs2X8Fn68/ATHl3OuB3pjSzR/Wlnqf7SYiKlUlajcWk2OuW7cOp0+fluuNGjVC165dYWnJ/60RmYuZOy/gm01x8nbfFjUwoWsjqMSkUURExhZuzp8/j1dffRUJCQmoX7++3DZp0iT4+Phgw4YNqFOnTlnUSUQGQlwS4tu/zuDnnRfk+nsv1MFHHerDwoLBhogMg97tx8OGDZMBRlzr5tChQ3IRF/arVauWvK8kZsyYgZo1a8LOzg6hoaGIiYkp1uOWL18uP1Bfe+21En1fItKPVqvDuPUn84PNJx398HFHPwYbIjLucLNr1y5MmTIFbm7/f36YSpUqySHi4j59rVixAiNHjsT48eNlUBKjsDp06IDk5OQnPu7y5cv48MMP0bp1a72/JxHpL1ejxahVR7F4/xWILPOf1xrj3RfYUktEJhBubG1tkZaW9sj29PR0OTRcX1OnTsWgQYMQERGBhg0bYtasWXBwcMD8+fOf2Oend+/emDBhAmrXrq339yQi/ai1wLAVx/Db4QRYqiwwrUcA+rSooXRZRESl0+emc+fOeOeddzBv3jyEhITIbdHR0RgyZIjsVKyPnJwcxMbGYsyYMYWugty2bVvs27fvsY/78ssv4eHhgcjISOzevfuJ3yM7O1sueVJTU+VXtVotF1JG3mvPY2D47mbcx5w4Fc7eS4aNlQrTe/jjZT8PHjsDxfeW8eCx0o8+r5Pe4Wb69OlyOHhYWBisra3lttzcXBlsfvjhB72eKyUlRbbCeHp6Ftou1uPiHozCeNiePXtksDpy5Eixvofo7CxaeB62efNm2UJEytqyZYvSJdATZOYCs09b4nK6CjYqHQbVUyP74kFsvKh0ZfQ0fG8ZDx6r4hEXEC6zcOPq6or169fj3Llzcii46EjYoEEDOaFmWROnw/r27YtffvkF7u7uxXqMaBUSfXoKttyIkV3t27eHs7NzGVZLT0vg4g3drl27/JBMhiUlPRsRUbG4nJ4OB0sd5oUHIbhW8d53pBy+t4wHj5V+8s68FEeJr48uJtDMCzQlHSkhAoq4Nk5SUlKh7WLdy8vrkf0vXLggOxJ36dIlf5tWq5VfrayscObMmUeGoos+QmJ5mPhF4i+T8ngcDNO1O5noO+8gLqVkoHIFGwyokymDDY+V8eB7y3jwWBWPPq9RiS4lKk4LNW7cWA7dFou4PXfuXL2fR3RADgoKwrZt2wqFFbEuTns9zM/PD8ePH5enpPIWcTrsxRdflLdFiwwRPZsLN9PRfdY+GWy8Xe3x68AQVOUZXCIyInq33IwbN06OcPr3v/+dH0BE598RI0bI692Izr76EKeMRB+e4OBg2UFZzF2VkZEhR0/lTdTp7e0t+87kBamHT5MJD28nIv2dvH4P/ebF4FZGDupUdsSSgaFwd7DCSaULIyIqy3Azc+ZM2eelZ8+e+dtE64m/v78MPPqGmx49euDmzZsyNCUmJiIgIACbNm3K72QsApMYQUVEZSv2ym30X3AAaVm5aFTVGYsGhKBSBVuO5CAi0w834oNOtLI8TJxeEqOmSmLo0KFyKcrOnTuf+NioqKgSfU8i+v92n7uJdxbF4r5ag+Y1K2Je/+ZwtmMfACIyTno3iYjRSqL15mFz5syRF9YjIuOy6UQiIqMOymDzfL3KWDQglMGGiIyaVUk7FIvrxLRo0SL/In7i9JHoH1Nw2LXom0NEhmtN7DV8vOYYNFodXmnshR/eDpQX6iMiMqtwc+LECTRr1ix/aHbekG6xiPvycCI9IsO2aN9lOQmm8FZQNUx6owmsLBlsiMgMw82OHTvKphIiKhc6nU7O6v3tX2fkekSrmvi8U0OoVPwPCRGZhhJfxI+IjDPYTN4Uh9m7HsyfMOzluhjRti5bWonIpJQo3Bw8eBArV66U/WzE5JcFrV27trRqI6JSJPrVfL7+BJZFx8v1sZ0aYGDr2kqXRURU6vQ+wb58+XK0bNlSziv122+/yaHhJ0+exPbt2+Hi4lL6FRLRM1NrtBi58ogMNqKRZvIbTRhsiMhk6R1uJk6ciP/+97/4448/5PQJYiZwMYN39+7dUb169bKpkohKLEutwbtLYrH+yHVYqSww/e1AvB3C9yoRmS69w40YIdWpUyd5W4QbMVWCOF8vpl8Q17ohIsORkZ2LAVEHsPV0MmytVJjTLwhdmlZVuiwiIsMKNxUrVkRaWpq8LeZ8yhv+fffuXWRmZpZ+hURUInczc9B7bjT2XrgFRxtLLBwQgpf8HkxrQkRkyvTuUPz8889jy5YtaNKkCd566y0MHz5c9rcR215++eWyqZKI9JKcliUnwIxLTIOrgzUWRoSgqc+DSWaJiExdscONaKERM2//9NNPyMrKkts+++wzWFtbY+/evXjzzTcxduzYsqyViIoh4e599JkbjUspGfBwssXiyFDU93JSuiwiIsMLN2LW7+bNm2PgwIF4++235TYxW/fo0aPLsj4i0sPFm+ky2Fy/l4VqFe2xdGAoalRyVLosIiLD7HOza9cuNGrUCKNGjUKVKlUQHh6O3bt3l211RFRsp66novvsfTLY1KnsiFVDwhhsiMgsFTvctG7dGvPnz8eNGzfw448/4vLly2jTpg3q1auHb775BomJiWVbKRE9VuyVO3h7zj6kpOegUVVnrBwchiou9kqXRURkHKOlHB0dERERIVtyzp49KzsVz5gxQ17jpmvXrmVTJRE91j/nU9B3XjRSs3IRXKMilg1qgUoVbJUui4hIMc80BbCvry8+/fRT2ZHYyckJGzZsKL3KiOipNp9MRMSCA8jM0aB1XXcsigyBi7210mURERnnxJl///23PE21Zs0a2bFYXKE4MjKydKsjosdadzgBo1YdlXNGdWjkiek9A2FrZal0WURExhVurl+/jqioKLmcP39ezjE1ffp0GWzE6SoiKh9L9l+Rk2DqdMAbzbwx5U1/WFk+U0MsEZH5hZtXXnkFW7duhbu7O/r164cBAwagfv36ZVsdET1i1q4LmPy/OHm7X1gNfNGlEVQqC6XLIiIyvnAjLta3evVqdO7cGZaWbPomKm86nQ7fbz6Ln3acl+vvv1gHH7avL+d2IyKiEoSb33//vbi7ElEp02p1+PLPU4jae1muf9LRD+++UEfpsoiITKtDMRGVj1yNFp+sOY41h65BNNJ8+a/G6NuihtJlEREZLIYbIgOWnavBB8uP4H8nEmGpssB3b/nj9cBqSpdFRGTQGG6IDNT9HA0GL4nF32dvwsZShR97BaJDIy+lyyIiMngMN0QGKDVLjcioAzhw+Q7srS0xp18QWtetrHRZRERGgeGGyMDczshB+PwYHE+4Byc7K0RFNEdQDTelyyIiMhoMN0QGJCk1C33mRuNccjrcHG2waEAIGnu7KF0WEZFRYbghMhBXb2ei99xoxN/OhJezHZYMDIWvRwWlyyIiMjoMN0QG4Hxymgw2SanZqO7mgKUDQ+Hj5qB0WURERonhhkhhJxLuod/8GNnXpp5nBSyODIWns53SZRERGS2GGyIFHbx8GxELDiAtOxf+1VywMCIEFR1tlC6LiMioMdwQKURcv2bw4ljcV2sQUssN88KD4WRnrXRZRERGj+GGSAGbTiRi2K+HkaPRok29ypjVJwj2NpyQloioNDDcEJWztYeu4aPVx6DR6vBqEy9M6xEIGyuV0mUREZkMhhuicrR432V8vv6kvN0tqBomv9EEVpYMNkREpYnhhqiczNx5Ad9sipO3+7esiXGdG0KlslC6LCIik8NwQ1TGdDodvtt8BjN2XJDr/37JFyPb1YOFBYMNEVFZYLghKkNarQ4T/jiJhfuuyPXRr/hhSJs6SpdFRGTSGG6IykiuRovRa49jdew1iEaaL//VGH1b1FC6LCIik8dwQ1QGcnK1+GDFYWw8nghLlQW+e8sfrwdWU7osIiKzwHBDVMru52gwZEksdp29CRtLFab3DETHxl5Kl0VEZDYYbohKUVqWGpELDyLm0m3YWaswp28wnq9XWemyiIjMCsMNUSm5k5GD8AUxOHbtHpxsrTA/ojma13RTuiwiIrPDcENUCpJTs9BnXjTOJqXDzdEGiwaEoLG3i9JlERGZJYYbomd07U4m+syNxuVbmfB0tsWSyFDU9XRSuiwiIrPFcEP0DC7eTEfvudG4cS8L1SraY9nAFqheyUHpsoiIzBrDDVEJnb6Rir7zopGSnoM6lR2xdGALeLnYKV0WEZHZY7ghKoHD8XcQPj8GqVm5aFjFGYsjQ1Cpgq3SZREREcMNkf72XkjBwIUHkZmjQbPqrlgQEQIXe2ulyyIiov/DcEOkh+1xSXh3ySFk52rRyreSvI6Noy3fRkREhoSfykTF9Oex6/hg+RHkanVo28ATP/UKhJ21pdJlERHRQxhuiIph5cGrGL3mGLQ6oGvTqvi+e1NYW6qULouIiIrAcEP0FAv+uYQJf5ySt3uG+OA/rzWRk2ESEZFhYrghegydTocZO87ju81n5fqg1rXw6asNYGHBYENEZMgYbogeE2y+2XQGs3ZdkOsftK2L4S/XZbAhIjICBtFpYMaMGahZsybs7OwQGhqKmJiYx+77yy+/oHXr1qhYsaJc2rZt+8T9ifSl1eowbv3J/GAztlMDfNC2HoMNEZGRUDzcrFixAiNHjsT48eNx6NAhNG3aFB06dEBycnKR++/cuRM9e/bEjh07sG/fPvj4+KB9+/ZISEgo99rJ9ORqtPhw9VEs3n8FIstMfL0JBraurXRZRERkTOFm6tSpGDRoECIiItCwYUPMmjULDg4OmD9/fpH7L126FO+99x4CAgLg5+eHuXPnQqvVYtu2beVeO5mW7FwNhi47jLWHEmSH4Wk9AtArtLrSZRERkTH1ucnJyUFsbCzGjBmTv02lUslTTaJVpjgyMzOhVqvh5uZW5P3Z2dlyyZOamiq/iseIhZSR99obyjG4n6PB+78ewe7zt2BtaYHpPZqibQMPg6lPSYZ2rOjJeLyMB4+VfvR5nRQNNykpKdBoNPD09Cy0XazHxcUV6zk++eQTVK1aVQaiokyaNAkTJkx4ZPvmzZtlCxEpa8uWLUqXgKxcYE6cJS6kWcBGpUNkPQ1yLh3ExktKV2ZYDOFYUfHxeBkPHisUuzHDLEZLTZ48GcuXL5f9cERn5KKIViHRp6dgy01ePx1nZ+dyrJYeTuDiDd2uXTtYWys3L9OdzBxELjqEC2mpqGBrhbl9AxFUo6Ji9RgiQzlWVDw8XsaDx0o/eWdeDD7cuLu7w9LSEklJSYW2i3UvL68nPva7776T4Wbr1q3w9/d/7H62trZyeZj4ReIvk/KUPA7JaVnoOz8WZ5LSUNHBGosjQ9HY20WRWowB3zPGhcfLePBYFY8+r5GiHYptbGwQFBRUqDNwXufgsLCwxz5uypQp+Oqrr7Bp0yYEBweXU7VkSq7dyUT3WftksPFwssXKwWEMNkREJkLx01LilFF4eLgMKSEhIZg2bRoyMjLk6CmhX79+8Pb2ln1nhG+++Qbjxo3DsmXL5LVxEhMT5fYKFSrIhehpLqVkoPcv+3H9XhaqVbTHsoEtUL0S+18REZkKxcNNjx49cPPmTRlYRFARQ7xFi0xeJ+P4+Hg5girPzJkz5Sirbt26FXoecZ2cL774otzrJ+MSl5iKPnNjkJKejdqVHbF0YCiquNgrXRYREZlSuBGGDh0ql6KIzsIFXb58uZyqIlNz7Npd9Jsfg7uZajSo4ozFkSFwr/BofywiIjJuBhFuiMpazKXbGBB1AOnZuQjwccXCiBC4OLADHxGRKWK4IZO36+xNDF58EFlqLcJqV8Iv4cFy2DcREZkmfsKTSdt0IhH//vUQ1BodXvLzwM+9m8HO2lLpsoiIqAwx3JDJ+u3wNXy46hg0Wh06NamC//YIgI2V4tOpERFRGWO4IZO0NPoKxq47AZ0O6BZUDd+86S8nwyQiItPHcEMmZ87fFzBx44O5yfq3rIlxnRtCxWBDRGQ2GG7IZOh0Okzbeg4/bDsn1997oQ4+6lAfFhYMNkRE5oThhkwm2Hy94TTm7nkwlbcINe+/6Kt0WUREpACGGzJ6osOw6F/za0y8XP+iS0P0b1VL6bKIiEghDDdk1NQaLT5cdRTrj1yH6FYz+Q1/dG/uo3RZRESkIIYbMlrZuRoMXXYYW04lwUplgWlvB6Czf1WlyyIiIoUx3JBRyszJxeDFsdh9LkVeu2Zm72Z4ucGDyVaJiMi8MdyQ0UnNUiMy6gAOXL4DBxtLzO0XjJa+7kqXRUREBoLhhozKnYwcObP38YR7cLKzQlRECIJqVFS6LCIiMiAMN2Q0ktOy0HduDM4kpcHN0QaLBoSgsbeL0mUREZGBYbgho5Bw9z56/7Ifl29lwsPJFksHhqKup5PSZRERkQFiuCGDdyklA33mRsuA4+1qj2WDQlGjkqPSZRERkYFiuCGDdiYxDX3mReNmWjZquztiycBQVHW1V7osIiIyYAw3ZLCOXbsrOw/fzVTDz8sJiyNDUdnJVumyiIjIwDHckEE6cPk2IhYcQHp2Lpr6uGJhRHO4OtgoXRYRERkBhhsyOLvP3cSgRQeRpdYipJYb5vdvjgq2/FUlIqLi4V8MMihiKoX3lx5CjkaL5+tVxuw+QbC3sVS6LCIiMiIMN2Qwfj96HSNWHJGzfHdo5InpPQNha8VgQ0RE+mG4IYOw4kA8Rq89Dp0OeD3QG99284eVpUrpsoiIyAgx3JDi5u+5hC//PCVv9wqtjv/8qzFUKgulyyIiIiPFcEOKmrnrIqZuPS9vD2pdC5++2gAWFgw2RERUcgw3pAidToc/4lXYmvAg2HzQti6Gv1yXwYaIiJ4Zww2VO61Wh682nsHWhAd9aj57tQEGPV9b6bKIiMhEMNxQuRIjoUavOYZVsdfk+oQuDRDeisGGiIhKD8MNlRu1RiuHev957AZEf+GedTToFeKjdFlERGRiGG6oXGSpNRi67BC2nk6GtaUFpr7lD+2VWKXLIiIiE8QLiVCZy8zJxcCFB2WwsbVSYU7fYHRs5Kl0WUREZKLYckNlKjVLjQELDuDglTtwsLHE3PBgtKzjDrVarXRpRERkohhuqMzcychBv/kxOJ5wD052Vlg4IATNqldUuiwiIjJxDDdUJpLTstB3bgzOJKXBzdEGiwaEoLG3i9JlERGRGWC4oVKXcPc++syNxqWUDHg42WLZoFD4ejgpXRYREZkJhhsqVZdTMtB7brQMON6u9jLY1KjkqHRZRERkRhhuqNScS0qTwSY5LRu13R2xZGAoqrraK10WERGZGYYbKhUnEu6h77xo3MlUo76nkww2lZ1slS6LiIjMEMMNPbPYK3fQf0EM0rJy4V/NBQsjQlDR0UbpsoiIyEwx3NAz2XshRV6gLzNHg+Y1K2J+/+ZwsrNWuiwiIjJjDDdUYjvikjFkSSyyc7VoXdcds/sGwcGGv1JERKQs/iWiEvnf8RsYtvww1Bod2jbwxE+9AmFnbal0WURERAw3pL81sdfw0eqj0OqAzv5V8N8eAbC25DRlRERkGBhuSC9L9l/B2HUn5O23gqph8pv+sFRZKF0WERFRPoYbKra5uy/iPxtOy9vhYTUwvksjqBhsiIjIwDDc0FPpdDpM33Ye/916Vq4PaVMHn3SsDwsLBhsiIjI8DDf01GAzeVMcZu+6KNdHtauHoS/5MtgQEZHBYrihx9Jqdfjij5NYtO+KXB/bqQEGtq6tdFlERERPxHBDRdJodfhkzTGsjr0G0Ujz9WtN0Cu0utJlERERPRXDDT1CrdFixIoj+PPYDYj+wt93b4rXA6spXRYREVGxMNxQIVlqDYYuO4Stp5NhbWmB6W8H4pUmVZQui4iIqNgYbihfZk4uBi+Oxe5zKbC1UmFWnyC86OehdFlERER6YbghKS1LjQFRB3Dg8h042FhibngwWtZxV7osIiIivTHcEO5m5qDf/Bgcu3YPTnZWiIoIQVCNikqXRUREVCIMN2bev2bTiUT8tOM8zienw83RBosGhKCxt4vSpREREZWYQcx2OGPGDNSsWRN2dnYIDQ1FTEzME/dftWoV/Pz85P5NmjTBxo0by61WUyCCzFd/nkKLSdvwwYojcr2yky1WvNOCwYaIiIye4i03K1aswMiRIzFr1iwZbKZNm4YOHTrgzJkz8PB4tDPr3r170bNnT0yaNAmdO3fGsmXL8Nprr+HQoUNo3LixIj+DMbXSLIuJR8yl2/nbq7rYoUfz6vIaNiLgEBERGTvFw83UqVMxaNAgREREyHURcjZs2ID58+dj9OjRj+z/ww8/oGPHjvjoo4/k+ldffYUtW7bgp59+ko9VSnauBjfTsmFo7t1X47dDCVhz6BruZKrlNnHtmpf8PNEr1Adt6nlwVm8iIjIpioabnJwcxMbGYsyYMfnbVCoV2rZti3379hX5GLFdtPQUJFp61q1bV+T+2dnZcsmTmpoqv6rVarmUlqNX76L7nCefTlOal7MtugdVQ7cgb1RxsZPbtJpcaDXlX0vea1+ax4DKBo+VceHxMh48VvrR53VSNNykpKRAo9HA09Oz0HaxHhcXV+RjEhMTi9xfbC+KOH01YcKER7Zv3rwZDg4OKC2X0wBrC0sYGjF1Ql0XHVp66tDQNQOqrDM4/M8ZHIZhEK1uZBx4rIwLj5fx4LEqnszMTOM5LVXWRKtQwZYe0XLj4+OD9u3bw9nZuVS/13ul+mymn8DFG7pdu3awtrZWuhx6Ah4r48LjZTx4rPSTd+bF4MONu7s7LC0tkZSUVGi7WPfy8iryMWK7Pvvb2trK5WHiF4m/TMrjcTAePFbGhcfLePBYFY8+r5GiQ8FtbGwQFBSEbdu25W/TarVyPSwsrMjHiO0F9xdE8n3c/kRERGReFD8tJU4ZhYeHIzg4GCEhIXIoeEZGRv7oqX79+sHb21v2nRGGDx+ONm3a4Pvvv0enTp2wfPlyHDx4EHPmzFH4JyEiIiJDoHi46dGjB27evIlx48bJTsEBAQHYtGlTfqfh+Ph4OYIqT8uWLeW1bcaOHYtPP/0UdevWlSOleI0bIiIiMohwIwwdOlQuRdm5c+cj29566y25EBERERnk9AtEREREpYXhhoiIiEwKww0RERGZFIYbIiIiMikMN0RERGRSGG6IiIjIpDDcEBERkUlhuCEiIiKTwnBDREREJsUgrlBcnnQ6nd5Tp1PpU6vVyMzMlMeBs+EaNh4r48LjZTx4rPST93c77+/4k5hduElLS5NffXx8lC6FiIiISvB33MXF5Yn7WOiKE4FMiFarxfXr1+Hk5AQLCwulyzHrBC4C5tWrV+Hs7Kx0OfQEPFbGhcfLePBY6UfEFRFsqlatWmhC7aKYXcuNeEGqVaumdBn0f8Qbmm9q48BjZVx4vIwHj1XxPa3FJg87FBMREZFJYbghIiIik8JwQ4qwtbXF+PHj5VcybDxWxoXHy3jwWJUds+tQTERERKaNLTdERERkUhhuiIiIyKQw3BAREZFJYbghIiIik8JwQ8/k66+/RsuWLeHg4ABXV9ci94mPj0enTp3kPh4eHvjoo4+Qm5tbaJ+dO3eiWbNmctSAr68voqKiHnmeGTNmoGbNmrCzs0NoaChiYmIK3Z+VlYX3338flSpVQoUKFfDmm28iKSmplH9i8/O0152ezd9//40uXbrIq66Kq6avW7eu0P1izMe4ceNQpUoV2Nvbo23btjh37lyhfW7fvo3evXvLC8GJ92FkZCTS09ML7XPs2DG0bt1aHkdxVdwpU6Y8UsuqVavg5+cn92nSpAk2btxYRj+1cZo0aRKaN28ur3AvPstee+01nDlzRu/PofL6TDRrYrQUUUmNGzdON3XqVN3IkSN1Li4uj9yfm5ura9y4sa5t27a6w4cP6zZu3Khzd3fXjRkzJn+fixcv6hwcHORznDp1Svfjjz/qLC0tdZs2bcrfZ/ny5TobGxvd/PnzdSdPntQNGjRI5+rqqktKSsrfZ8iQITofHx/dtm3bdAcPHtS1aNFC17Jly3J4FUxXcV53ejbiPfHZZ5/p1q5dK0au6n777bdC90+ePFm+t9atW6c7evSormvXrrpatWrp7t+/n79Px44ddU2bNtXt379ft3v3bp2vr6+uZ8+e+fffu3dP5+npqevdu7fuxIkTul9//VVnb2+vmz17dv4+//zzj3zfTZkyRb4Px44dq7O2ttYdP368nF4Jw9ehQwfdggUL5Gt45MgR3auvvqqrXr26Lj09vdifQ+X5mWjOGG6oVIg3fFHhRrxxVSqVLjExMX/bzJkzdc7Ozrrs7Gy5/vHHH+saNWpU6HE9evSQHyR5QkJCdO+//37+ukaj0VWtWlU3adIkuX737l35Qbxq1ar8fU6fPi3/WOzbt6+Uf1rz8bTXnUrXw+FGq9XqvLy8dN9++23+NvG7bmtrKwOKIP74iccdOHAgf5///e9/OgsLC11CQoJc//nnn3UVK1bMf88Jn3zyia5+/fr56927d9d16tSpUD2hoaG6wYMHl9FPa/ySk5Pla79r165ifw6V12eiueNpKSpT+/btk83bnp6e+ds6dOggJ4w7efJk/j6iqb0gsY/YLuTk5CA2NrbQPmKOMLGet4+4X61WF9pHNK9Xr149fx/ST3Fedypbly5dQmJiYqFjIObWEacg8o6B+CpORQUHB+fvI/YXxyo6Ojp/n+effx42NjaF3mPilMqdO3eK9T6kR927d09+dXNzK/bnUHl9Jpo7hhsqU+KDueCbWMhbF/c9aR/xZr9//z5SUlKg0WiK3Kfgc4gP7of7/RTch/RTnNedylbe6/y0333Rb6MgKysr+Qf3ae+xgt/jcfvwWBdNq9Xigw8+QKtWrdC4ceNifw6V12eiuWO4oUeMHj1admx80hIXF6d0mUREihGdhk+cOIHly5crXQoVwaqojWTeRo0ahf79+z9xn9q1axfruby8vB7pwZ83ckDcl/f14dEEYl2M/BCjQywtLeVS1D4Fn0M01d69e7fQ/5oK7kP6cXd3f+rrTmUr73UWr7kYLZVHrAcEBOTvk5ycXOhxYuSNGEH1tPdYwe/xuH14rB81dOhQ/Pnnn3KkW7Vq1fK3F+dzqLw+E80dW27oEZUrV5bniZ+0FDx3/yRhYWE4fvx4oQ/fLVu2yDdpw4YN8/fZtm1boceJfcR2QXyvoKCgQvuIJmGxnrePuN/a2rrQPqI/gRhymbcP6ac4rzuVrVq1ask/VgWPgTg1IfrS5B0D8VX8MRV9MPJs375dHivRNydvH/GHWPQHKfgeq1+/PipWrFis9yE9GJYvgs1vv/0mX2NxfAoqzudQeX0mmj2lezSTcbty5YoczjhhwgRdhQoV5G2xpKWlFRr22L59ezl0UgxlrFy5cpHDHj/66CM5smDGjBlFDnsUI0SioqLk6JB33nlHDnssOOJADMEUwzK3b98uh2CGhYXJhUquOK87PRvxXsl734iPZHFpBXFbvLfyhoKL13z9+vW6Y8eO6f71r38VORQ8MDBQFx0drduzZ4+ubt26hYaCi1E8Yih437595TBmcVzFe+7hoeBWVla67777Tr4Px48fz6HgD3n33XflqNCdO3fqbty4kb9kZmYW+3OoPD8TzRnDDT2T8PBw+YH88LJjx478fS5fvqx75ZVX5HU1xPUcRo0apVOr1YWeR+wfEBAgr9tQu3ZtObT8YeJaD+JDQ+wjhkGKa3oUJD7s33vvPTnkVXwwvP766/KDh57N0153ejbid7+o95B4b+UNB//8889lOBF/zF5++WXdmTNnCj3HrVu3ZJgR/8EQQ4ojIiLy/4ORR1wj57nnnpPP4e3tLUPTw1auXKmrV6+ePNZiKPKGDRvK+Kc3LkUdJ7EU/LwqzudQeX0mmjML8Y/SrUdEREREpYV9boiIiMikMNwQERGRSWG4ISIiIpPCcENEREQmheGGiIiITArDDREREZkUhhsiIiIyKQw3REREZFIYboiISskLL7wACwsLuRw5cqTIfS5fvpy/T97kl0RUuhhuiOiJxAzxr7322iPbd+7cKf9Ai0kbS0txnzNvP7GoVCq4uLggMDAQH3/8MW7cuKH3961ZsyamTZuG0jBo0CBZQ+PGjQuFmbyw4+PjI+8fNWpUqXw/InoUww0RGS0x4/L169dx4MABfPLJJ9i6dasMFWLWZaU4ODjImbytrKyKvN/S0lLeX6FChXKvjchcMNwQUanZs2cPWrduDXt7e9lCMWzYMGRkZOTfv3jxYgQHB8PJyUn+ge/VqxeSk5PzWzhefPFFebtixYqytUO0Gj2Jh4eHfJ569erh7bffxj///IPKlSvj3XffLXSq6IMPPij0ONESlffc4v4rV65gxIgR+a1BomZnZ2esXr260OPWrVsHR0dHpKWllcKrRURlheGGiErFhQsX0LFjR7z55ps4duwYVqxYIcPO0KFD8/dRq9X46quvcPToURkURKDJCxkiDK1Zsya/RUacuvnhhx/0qkGEqiFDhsiQkxeanmbt2rWoVq0avvzyS/k9xSICjAhLCxYsKLSvWO/WrZsMZ0RkuIpuNyUiKuDPP/985DSKRqMptD5p0iT07t07v5Wkbt26mD59Otq0aYOZM2fCzs4OAwYMyN+/du3a8v7mzZsjPT1dPr+bm1t+i4yrq2uJavXz85NfRXASz/M04nuKU0V5rUl5Bg4ciJYtW8qwU6VKFRmWNm7cKE99EZFhY8sNET2VOF0kOsQWXObOnVtoH9EaExUVJUNK3tKhQwdotVpcunRJ7hMbG4suXbqgevXqMkyI4CPEx8eXWq06nU5+FaeXnkVISAgaNWqEhQsXyvUlS5agRo0aeP7550ulTiIqO2y5IaKnEqdpfH19C227du1aoXXR+jJ48GDZz+ZhIsyIfiwi7Ihl6dKlsm+MCDViPScnp9RqPX36dP4IKEGMpsoLPAVPjxWHaL2ZMWMGRo8eLU9JRUREPHNoIqKyx3BDRKWiWbNmOHXq1CMhKI8YwXTr1i1MnjxZ9q8RDh48WGgfGxubIk95Fdf9+/cxZ84c2boiwpMgvhYcHi6e+8SJE/mdl/O+b1Hfs0+fPnJ4uTh9Jn628PDwEtVFROWLp6WIqFSIodh79+6VHYjFaatz585h/fr1+R2KReuNCBE//vgjLl68iN9//112Li5InPYRLSOij8/Nmzdla9CTiH4wiYmJ8nstX74crVq1QkpKiuzjk+ell17Chg0b5BIXFydHUj18HR3RyvP3338jISFBPj6PGLX1xhtv4KOPPkL79u1lx2MiMnwMN0RUKvz9/bFr1y6cPXtWDgcXF9UbN24cqlatmt+CIvrkrFq1Cg0bNpQtON99912h5/D29saECRPkaSBPT89CI62KUr9+ffn8QUFB8vnatm0rW2XE8+cRnZhFi0u/fv1kHx/Rkblgq40gRkqJDsh16tTJb/HJExkZKU+bFewMrQ/R50h43HVviKj0WegePhlNRESFrs0jroEjLhaYd9rsccQ1c8SUCgWvdrx//36EhYXJlih3d/f87V988YUcDv+4aRqIqOTYckNEVITMzEx57R7RIiQ6Sj8t2OT5+eef5Ugx0cfo/Pnz+Pbbb9G0adP8YCM6UYv7J06cWMY/AZH5YssNEVERRMvK119/LTsni75DxZkuQfTZEZ2ahdu3b+e35MyaNUuethNyc3PlKTDB1tY2v3M1EZUehhsiIiIyKTwtRURERCaF4YaIiIhMCsMNERERmRSGGyIiIjIpDDdERERkUhhuiIiIyKQw3BAREZFJYbghIiIimJL/B2d8m7s0QfnEAAAAAElFTkSuQmCC" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 43 }, { + "metadata": { + "tags": [ + "exercise" + ] + }, "cell_type": "markdown", - "metadata": {}, "source": [ "
\n", "Inline Exercise:\n", @@ -744,27 +1476,27 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" ] }, + "cell_type": "code", + "source": "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor", "outputs": [], - "source": [ - "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor" - ] + "execution_count": null }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:02.101331Z", + "start_time": "2025-06-06T17:05:00.157447Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# Todo: generate a figure of heat duty vs. mole fraction of Benzene in the vapor\n", "Q = []\n", @@ -797,18 +1529,247 @@ "plt.xlabel(\"Heat Duty [J]\")\n", "plt.ylabel(\"Vapor Benzene Mole Fraction [-]\")\n", "plt.show()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulating with Q = -17000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -16142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -15285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -14428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -13571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -12714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -11000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -10142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -9285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -8428.57142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -7571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -6714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5857.142857142857\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -5000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -4142.857142857143\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -3285.7142857142862\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -2428.5714285714294\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -1571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = -714.2857142857156\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 142.8571428571413\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 1857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 2714.2857142857138\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 3571.4285714285725\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 4428.5714285714275\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 5285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 6142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 7857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 8714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 9571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 10428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 11285.714285714286\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 12142.857142857141\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 13857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 14714.285714285714\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 15571.428571428569\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 16428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 17285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 18142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 19857.142857142855\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 20714.28571428571\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 21571.428571428572\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 22428.571428571428\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 23285.714285714283\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 24142.857142857145\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n", + "Simulating with Q = 25000.0\n", + "WARNING: model contains export suffix 'scaling_factor' that contains 7\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "... solve successful.\n" + ] + }, + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "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" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 44 }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "Recall that the IDAES framework is an equation-oriented modeling environment. This means that we can specify \"design\" problems natively. That is, there is no need to have our specifications on the inlet alone. We can put specifications on the outlet as long as we retain a well-posed, square system of equations.\n", "\n", "For example, we can remove the specification on heat duty and instead specify that we want the mole fraction of Benzene in the vapor outlet to be equal to 0.6. The mole fraction is not a native variable in the property block, so we cannot use \"fix\". We can, however, add a constraint to the model.\n", "\n", "Note that we have been executing a number of solves on the problem, and may not be sure of the current state. To help convergence, therefore, we will first call initialize, then add the new constraint and solve the problem. Note that the reference for the mole fraction of Benzene in the vapor outlet is `m.fs.flash.vap_outlet.mole_frac_comp[0, \"benzene\"]`.\n", - "\n", + "\n" + ] + }, + { + "metadata": { + "tags": [ + "exercise" + ] + }, + "cell_type": "markdown", + "source": [ "
\n", "Inline Exercise:\n", "Fill in the missing code below and add a constraint on the mole fraction of Benzene (to a value of 0.6) to find the required heat duty.\n", @@ -816,14 +1777,16 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.363302Z", + "start_time": "2025-06-06T17:05:04.960601Z" + }, "tags": [ "exercise" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -839,17 +1802,118 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 136\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 41\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.07e-08 1.01e-04 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.46e+00 2.42e-01 -1.0 4.86e+02 - 9.90e-01 1.00e+00f 1\n", + " 2 0.0000000e+00 5.55e+01 5.60e-03 -1.0 3.00e+03 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 1.91e+00 4.24e-05 -1.0 5.68e+02 - 1.00e+00 1.00e+00h 1\n", + " 4 0.0000000e+00 1.53e-05 1.90e-06 -2.5 1.35e+00 - 1.00e+00 1.00e+00h 1\n", + " 5 0.0000000e+00 4.66e-10 1.50e-09 -3.8 8.72e-03 - 1.00e+00 1.00e+00h 1\n", + " 6 0.0000000e+00 2.18e-11 1.84e-11 -5.7 1.92e-03 - 1.00e+00 1.00e+00h 1\n", + " 7 0.0000000e+00 1.46e-11 2.51e-14 -8.6 2.10e-04 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 7\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 2.5059035640133008e-14 2.5059035640133008e-14\n", + "Constraint violation....: 4.8801876740451558e-13 1.4551915228366852e-11\n", + "Complementarity.........: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "Overall NLP error.......: 2.5059101787473095e-09 2.5059101787473095e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 9\n", + "Number of objective gradient evaluations = 8\n", + "Number of equality constraint evaluations = 9\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 8\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 7\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.002\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 4059.3 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.51773 0.48227 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60690 0.38524 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.39310 0.61476 \n", + " temperature kelvin 368.00 368.85 368.85 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 45 }, { - "cell_type": "code", - "execution_count": null, "metadata": { + "ExecuteTime": { + "end_time": "2025-06-06T17:05:05.768445Z", + "start_time": "2025-06-06T17:05:05.378930Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "cell_type": "code", "source": [ "# re-initialize the model - this may or may not be required depending on current state but safe to initialize\n", "m.fs.flash.heat_duty.fix(0)\n", @@ -868,7 +1932,102 @@ "\n", "# Check stream condition\n", "m.fs.flash.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: model contains export suffix 'scaling_factor' that contains 6\n", + "component keys that are not exported as part of the NL file. Skipping.\n", + "Ipopt 3.13.2: \n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma27.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 137\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 72\n", + "\n", + "Total number of variables............................: 42\n", + " variables with only lower bounds: 3\n", + " variables with lower and upper bounds: 10\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 42\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.40e-02 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + " 1 0.0000000e+00 1.64e+02 7.01e-02 -1.0 5.15e+03 - 9.87e-01 1.00e+00h 1\n", + " 2 0.0000000e+00 9.59e-02 2.03e-03 -1.0 7.07e+01 - 9.90e-01 1.00e+00h 1\n", + " 3 0.0000000e+00 6.96e-08 2.50e-06 -1.0 4.13e-01 - 9.98e-01 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 3\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 8.9151738215745240e-11 6.9550878833979368e-08\n", + "\n", + "\n", + "Number of objective function evaluations = 4\n", + "Number of objective gradient evaluations = 4\n", + "Number of equality constraint evaluations = 4\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 4\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 3\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.001\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n", + "\n", + "====================================================================================\n", + "Unit : fs.flash Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 5083.6 : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " flow_mol mole / second 1.0000 0.54833 0.45167 \n", + " mole_frac_comp benzene dimensionless 0.50000 0.60000 0.37860 \n", + " mole_frac_comp toluene dimensionless 0.50000 0.40000 0.62140 \n", + " temperature kelvin 368.00 369.07 369.07 \n", + " pressure pascal 1.0132e+05 1.0132e+05 1.0132e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 46 } ], "metadata": { @@ -893,4 +2052,4 @@ }, "nbformat": 4, "nbformat_minor": 3 -} +} \ No newline at end of file diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb index a7645f92..abfc2b04 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.ipynb @@ -2,18 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -23,7 +25,9 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "markdown", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
\n", + "Maintainer: Tanner Polley
\n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
\n", + "     2 Building a Model
\n", + "     3 Scaling the Model
\n", + "     4 Specifying the Model
\n", + "     5 Initializing the Model
\n", + "     6 Solving the Model
\n", + "     7 Analyzing and Visualizing the Results
\n", + "     8 Optimizing the Model
\n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,14 +114,17 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -110,40 +132,51 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", "from pyomo.network import Arc, SequentialDecomposition" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "source": [ "from idaes.core import FlowsheetBlock" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -151,8 +184,14 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" - ] + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,30 +205,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.952476Z", + "start_time": "2025-11-20T21:46:09.949367Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ] + ], + "outputs": [], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.963041Z", + "start_time": "2025-11-20T21:46:09.957319Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "markdown", @@ -200,24 +247,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" - ] + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -232,33 +282,49 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" - ] + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -269,34 +335,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -304,11 +382,17 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
\n", "Inline Exercise:\n", @@ -325,26 +409,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.121709Z", + "start_time": "2025-11-20T21:46:10.119134Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.145853Z", + "start_time": "2025-11-20T21:46:10.127921Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -354,7 +444,9 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ] + ], + "outputs": [], + "execution_count": 13 }, { "cell_type": "markdown", @@ -370,29 +462,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -412,66 +512,115 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "![](HDA_flowsheet.png) \n", - "\n", + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, + "source": [ "
\n", "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
\n", - "\n" + "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide.\n", + "
" ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.245319Z", + "start_time": "2025-11-20T21:46:10.239913Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.254153Z", + "start_time": "2025-11-20T21:46:10.248481Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ] + ], + "outputs": [], + "execution_count": 19 }, { "cell_type": "markdown", @@ -482,17 +631,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, { "cell_type": "markdown", "metadata": {}, @@ -502,20 +679,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -529,18 +711,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "markdown", @@ -551,14 +742,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -575,14 +771,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -593,78 +794,112 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.409008Z", + "start_time": "2025-11-20T21:46:10.382157Z" + } }, - "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 29" - ] + ], + "outputs": [], + "execution_count": 28 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" - ] + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
    \n", "
  • FH2 = 0.30 mol/s
  • \n", "
  • FCH4 = 0.02 mol/s
  • \n", @@ -677,39 +912,59 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" - ] + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ] + ], + "outputs": [], + "execution_count": 31 }, { "cell_type": "markdown", @@ -720,23 +975,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ] + ], + "outputs": [], + "execution_count": 32 }, { "cell_type": "markdown", @@ -747,17 +1010,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ] + ], + "outputs": [], + "execution_count": 33 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
    \n", "Inline Exercise:\n", @@ -773,30 +1045,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.472509Z", + "start_time": "2025-11-20T21:46:10.467229Z" + } }, - "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ] + ], + "outputs": [], + "execution_count": 34 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.482109Z", + "start_time": "2025-11-20T21:46:10.475567Z" + } }, - "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ] + ], + "outputs": [], + "execution_count": 35 }, { "cell_type": "markdown", @@ -807,20 +1087,29 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ] + ], + "outputs": [], + "execution_count": 36 }, { "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "Inline Exercise:\n", + "metadata": { + "tags": [ + "exercise" + ] + }, + "source": [ + "
    \n", + "Inline Exercise:\n", "We have now defined all the feed conditions and the inputs required for the unit models. The system should now have 0 degrees of freedom i.e. should be a square problem. Please check that the degrees of freedom is 0. \n", "\n", "Use Shift+Enter to run the cell once you have typed in your code. \n", @@ -829,68 +1118,101 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.503512Z", + "start_time": "2025-11-20T21:46:10.495838Z" + } }, - "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ] + ], + "outputs": [], + "execution_count": 37 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.535421Z", + "start_time": "2025-11-20T21:46:10.507798Z" + } }, - "outputs": [], "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 38 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.568992Z", + "start_time": "2025-11-20T21:46:10.542995Z" + } }, - "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" - ] + ], + "outputs": [], + "execution_count": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", "\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", "\n", - "![](HDA_flowsheet.png) \n" + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", + "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", + "\n", + "\n", + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "source": [ "seq = SequentialDecomposition()\n", "seq.options.select_tear_method = \"heuristic\"\n", @@ -901,7 +1223,9 @@ "G = seq.create_graph(m)\n", "heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", "order = seq.calculation_order(G)" - ] + ], + "outputs": [], + "execution_count": 40 }, { "cell_type": "markdown", @@ -912,13 +1236,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], + "execution_count": 41 }, { "cell_type": "markdown", @@ -929,15 +1266,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + } }, - "outputs": [], "source": [ "for o in order:\n", " print(o[0].name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], + "execution_count": 42 }, { "cell_type": "markdown", @@ -948,25 +1302,30 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -974,7 +1333,9 @@ "\n", "# Pass the tear_guess to the SD tool\n", "seq.set_guesses_for(m.fs.H101.inlet, tear_guesses)" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "markdown", @@ -985,9 +1346,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "source": [ "def function(unit):\n", " try:\n", @@ -996,7 +1360,9 @@ " except InitializationError:\n", " solver = get_solver()\n", " solver.solve(unit)" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "markdown", @@ -1007,165 +1373,1290 @@ }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "source": "seq.run(m, function)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "execution_count": 45 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, + "source": [ + "from idaes.core.util.initialization import propagate_state" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", + "\n", + "We will first ensure that are current degrees of freedom is still zero" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "source": "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")", + "outputs": [], + "execution_count": 47 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ], + "outputs": [], + "execution_count": 48 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ], + "outputs": [], + "execution_count": 49 + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ], "outputs": [], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "seq.run(m, function)" + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.35e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.07e+03 1.08e+01 -1.0 1.21e+03 - 8.49e-01 6.80e-01h 1\n", + " 2 0.0000000e+00 1.66e+02 4.55e+02 -1.0 7.65e+02 - 9.90e-01 8.44e-01h 1\n", + " 3 0.0000000e+00 5.53e+00 2.00e+02 -1.0 1.30e+02 - 9.90e-01 9.67e-01h 1\n", + " 4 0.0000000e+00 5.22e-02 8.91e+03 -1.0 4.05e+00 - 1.00e+00 9.91e-01h 1\n", + " 5 0.0000000e+00 1.46e-04 1.02e+04 -1.0 3.80e-02 - 1.00e+00 9.97e-01h 1\n", + " 6 0.0000000e+00 9.46e-11 6.27e-01 -1.0 1.06e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 6\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 7\n", + "Number of objective gradient evaluations = 7\n", + "Number of equality constraint evaluations = 7\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 7\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 6\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.009\n", + "Total CPU secs in NLP function evaluations = 0.001\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 51 + }, { "cell_type": "markdown", "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
    \n", "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", + "Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", + "\n", + "solver = get_solver(solver_options=optarg)
    \n", "results = solver.solve(m, tee=True)\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
    \n", - "\n" + "Use Shift+Enter to run the cell once you have typed in your code.\n", + "
    \n" ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.285774Z", + "start_time": "2025-11-20T21:46:17.281657Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", "\n", - "\n", "# Solve the model" - ] + ], + "outputs": [], + "execution_count": 54 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.382669Z", + "start_time": "2025-11-20T21:46:17.293013Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.64e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.84e+01 4.18e+00 -1.0 4.14e-01 - 9.90e-01 9.89e-01h 1\n", + " 2 0.0000000e+00 1.82e-01 3.87e+00 -1.0 3.76e-01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 6.96e-04 4.53e+02 -1.0 3.70e-02 - 9.92e-01 9.96e-01h 1\n", + " 4 0.0000000e+00 4.52e-09 8.75e-01 -1.0 3.82e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 4\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 5\n", + "Number of objective gradient evaluations = 5\n", + "Number of equality constraint evaluations = 5\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 5\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 4\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.008\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 55 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.393870Z", + "start_time": "2025-11-20T21:46:17.390132Z" + } }, - "outputs": [], "source": [ "# Check solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 56 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", + "## 7 Analyze the results\n", "\n", - "\n", - "What is the total operating cost? " + "\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "noauto" + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.403453Z", + "start_time": "2025-11-20T21:46:17.400372Z" + } + }, + "source": [ + "# m.fs.visualize(\"HDA-Flowsheet\")" + ], "outputs": [], + "execution_count": 57 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate mole / second 0.30005 0.32004 2.0320 2.0320 2.0320 1.7648 0.26712 1.4119 1.4119 0.17224 0.094878 0.35297\n", + " Total Mole Fraction benzene dimensionless 6.6656e-05 6.2492e-05 0.058732 0.058732 0.17408 0.084499 0.76595 0.084499 0.084499 0.82430 0.66001 0.084499\n", + " Total Mole Fraction toluene dimensionless 0.99987 6.2492e-05 0.15380 0.15380 0.038450 0.0088437 0.23405 0.0088437 0.0088437 0.17570 0.33999 0.0088437\n", + " Total Mole Fraction hydrogen dimensionless 3.3328e-05 0.93738 0.27683 0.27683 0.16148 0.18592 6.9600e-09 0.18592 0.18592 1.0794e-08 1.1376e-15 0.18592\n", + " Total Mole Fraction methane dimensionless 3.3328e-05 0.062492 0.51064 0.51064 0.62599 0.72074 2.6982e-08 0.72074 0.72074 4.1844e-08 4.4103e-15 0.72074\n", + " Temperature kelvin 303.20 303.20 324.54 600.00 822.07 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 58 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "What is the total operating cost?" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 424513.9640158265\n" + ] + } + ], + "execution_count": 59 + }, + { + "cell_type": "code", "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.571498Z", + "start_time": "2025-11-20T21:46:17.493194Z" + } }, - "outputs": [], "source": [ "import pytest\n", "\n", - "assert value(m.fs.operating_cost) == pytest.approx(419122.3387, abs=1e-3)" - ] + "assert value(m.fs.operating_cost) == pytest.approx(424513.9645, abs=1e-3)" + ], + "outputs": [], + "execution_count": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, "source": [ "m.fs.F102.report()\n", "\n", "print()\n", "print(\"benzene purity = \", value(m.fs.purity))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.0 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.26712 - - \n", + " Total Mole Fraction benzene dimensionless 0.76595 - - \n", + " Total Mole Fraction toluene dimensionless 0.23405 - - \n", + " Total Mole Fraction hydrogen dimensionless 6.9600e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.6982e-08 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555956\n" + ] + } + ], + "execution_count": 61 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.619054Z", + "start_time": "2025-11-20T21:46:17.613393Z" + } }, - "outputs": [], "source": [ "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", - "\n", - "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7352.4828, abs=1e-3)\n", + "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.03097, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 62 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
    \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
    \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1174,25 +2665,30 @@ "\n", "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
    \n" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate mole / second 2.0320 1.7648 \n", + "Total Mole Fraction benzene dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction toluene dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction hydrogen dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction methane dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 822.07 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1219,12 +2715,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] + ], + "outputs": [], + "execution_count": 64 }, { "cell_type": "markdown", @@ -1235,19 +2736,28 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ] + ], + "outputs": [], + "execution_count": 65 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
    \n", "Inline Exercise:\n", @@ -1260,43 +2770,55 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.707409Z", + "start_time": "2025-11-20T21:46:17.704141Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ] + ], + "outputs": [], + "execution_count": 66 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.720592Z", + "start_time": "2025-11-20T21:46:17.717532Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ] + ], + "outputs": [], + "execution_count": 67 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.759351Z", + "start_time": "2025-11-20T21:46:17.728327Z" + } }, - "outputs": [], "source": [ "assert degrees_of_freedom(m) == 5" - ] + ], + "outputs": [], + "execution_count": 68 }, { "cell_type": "markdown", @@ -1315,17 +2837,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ] + ], + "outputs": [], + "execution_count": 69 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
    \n", "Inline Exercise:\n", @@ -1337,31 +2868,39 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.797044Z", + "start_time": "2025-11-20T21:46:17.794614Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature" - ] + ], + "outputs": [], + "execution_count": 70 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.812504Z", + "start_time": "2025-11-20T21:46:17.807564Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.R101.outlet.temperature[0].setlb(600)\n", "m.fs.R101.outlet.temperature[0].setub(800)" - ] + ], + "outputs": [], + "execution_count": 71 }, { "cell_type": "markdown", @@ -1372,9 +2911,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)\n", @@ -1382,7 +2924,9 @@ "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] + ], + "outputs": [], + "execution_count": 72 }, { "cell_type": "markdown", @@ -1393,19 +2937,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ] + ], + "outputs": [], + "execution_count": 73 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
    \n", "Inline Exercise:\n", @@ -1417,32 +2973,43 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.862411Z", + "start_time": "2025-11-20T21:46:17.859385Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ] + ], + "outputs": [], + "execution_count": 74 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.876414Z", + "start_time": "2025-11-20T21:46:17.872250Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] >= 0.15\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", ")" - ] + ], + "outputs": [], + "execution_count": 75 }, { "cell_type": "markdown", @@ -1453,12 +3020,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] + ], + "outputs": [], + "execution_count": 76 }, { "cell_type": "markdown", @@ -1472,43 +3044,161 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, "source": [ "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 151\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 4.2451396e+05 4.00e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 4.2182392e+05 4.00e+04 6.94e+00 -1.0 3.47e+07 - 3.71e-05 1.25e-05f 1\n", + " 2 4.2170773e+05 4.00e+04 8.41e+01 -1.0 1.49e+06 - 3.32e-04 1.53e-05f 1\n", + " 3 4.1795462e+05 4.00e+04 6.82e+01 -1.0 1.43e+06 - 4.98e-04 5.60e-04f 1\n", + " 4 3.0650178e+05 4.00e+04 3.09e+02 -1.0 1.26e+07 - 2.61e-05 1.17e-03f 1\n", + " 5 3.0553183e+05 3.99e+04 3.25e+04 -1.0 1.48e+05 - 1.28e-01 1.02e-03f 1\n", + " 6 3.0565526e+05 3.91e+04 5.25e+04 -1.0 3.99e+04 - 1.13e-01 2.09e-02h 2\n", + " 7 3.0601574e+05 3.59e+04 4.21e+04 -1.0 3.91e+04 - 5.17e-02 8.21e-02h 2\n", + " 8 3.0674242e+05 2.95e+04 8.41e+04 -1.0 3.59e+04 - 4.38e-01 1.79e-01h 1\n", + " 9 3.1153051e+05 1.11e+04 5.73e+04 -1.0 2.95e+04 - 8.56e-01 6.23e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 3.1154545e+05 1.09e+04 5.69e+04 -1.0 1.19e+04 - 6.57e-02 2.37e-02h 1\n", + " 11 3.1159568e+05 1.08e+04 5.66e+04 -1.0 1.68e+04 - 2.23e-02 8.97e-03h 1\n", + " 12 3.1610911e+05 2.56e+03 2.13e+05 -1.0 1.68e+04 - 9.47e-01 7.94e-01h 1\n", + " 13 3.1708718e+05 1.16e+03 9.56e+04 -1.0 4.45e+03 - 9.90e-01 5.53e-01h 1\n", + " 14 3.1796760e+05 4.06e+02 1.14e+03 -1.0 1.27e+04 - 9.95e-01 9.87e-01h 1\n", + " 15 3.1802429e+05 5.35e+00 6.53e+02 -1.0 8.29e+01 - 1.00e+00 9.89e-01h 1\n", + " 16 3.1802524e+05 1.77e-04 5.89e+02 -1.0 5.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 17 3.1802492e+05 5.34e-06 1.83e+06 -2.5 1.32e+00 - 3.33e-01 1.00e+00f 1\n", + " 18 3.1802492e+05 1.70e-09 9.74e-03 -2.5 2.42e-02 - 1.00e+00 1.00e+00h 1\n", + " 19 3.1802491e+05 4.41e-09 1.03e-01 -5.7 3.83e-02 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 3.1802491e+05 2.39e-03 8.22e-09 -5.7 2.88e+01 - 1.00e+00 1.00e+00h 1\n", + " 21 3.1802491e+05 8.00e-11 9.72e-09 -5.7 4.08e-04 - 1.00e+00 1.00e+00h 1\n", + " 22 3.1802491e+05 2.47e-03 1.19e-01 -8.6 2.93e+01 - 9.99e-01 1.00e+00h 1\n", + " 23 3.1802491e+05 2.41e+02 2.13e-09 -8.6 9.27e+03 - 1.00e+00 1.00e+00h 1\n", + " 24 3.1802491e+05 6.96e-03 3.66e-09 -8.6 1.88e+02 - 1.00e+00 1.00e+00h 1\n", + " 25 3.1802491e+05 3.61e-06 1.59e-09 -8.6 1.21e+00 - 1.00e+00 1.00e+00h 1\n", + " 26 3.1802491e+05 2.29e-05 4.82e-09 -8.6 3.07e+00 - 1.00e+00 1.00e+00h 1\n", + " 27 3.1802491e+05 9.42e-07 5.47e-09 -8.6 6.24e-01 - 1.00e+00 1.00e+00h 1\n", + " 28 3.1802491e+05 1.16e-10 9.67e-09 -8.6 3.01e+00 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 28\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 3.1802490940142004e+05 3.1802490940142004e+05\n", + "Dual infeasibility......: 9.6706583658121551e-09 9.6706583658121551e-09\n", + "Constraint violation....: 1.1641532182693481e-10 1.1641532182693481e-10\n", + "Complementarity.........: 2.5059899579272651e-09 2.5059899579272651e-09\n", + "Overall NLP error.......: 2.2246107350021195e-10 9.6706583658121551e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 35\n", + "Number of objective gradient evaluations = 29\n", + "Number of equality constraint evaluations = 35\n", + "Number of inequality constraint evaluations = 35\n", + "Number of equality constraint Jacobian evaluations = 29\n", + "Number of inequality constraint Jacobian evaluations = 29\n", + "Number of Lagrangian Hessian evaluations = 28\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.036\n", + "Total CPU secs in NLP function evaluations = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 77 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.045752Z", + "start_time": "2025-11-20T21:46:18.041549Z" + } }, - "outputs": [], "source": [ "# Check for solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 78 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1523,21 +3213,107 @@ "print()\n", "print(\"Overhead loss in F101\")\n", "m.fs.F101.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 318024.90940142004\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8369.3 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.28812 - - \n", + " Total Mole Fraction benzene dimensionless 0.75463 - - \n", + " Total Mole Fraction toluene dimensionless 0.24537 - - \n", + " Total Mole Fraction hydrogen dimensionless 7.5018e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.5957e-08 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8188295888411846\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -66423. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 1.9480 - - \n", + " Total Mole Fraction benzene dimensionless 0.13952 - - \n", + " Total Mole Fraction toluene dimensionless 0.039059 - - \n", + " Total Mole Fraction hydrogen dimensionless 0.18417 - - \n", + " Total Mole Fraction methane dimensionless 0.63725 - - \n", + " Temperature kelvin 763.51 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 79 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.093619Z", + "start_time": "2025-11-20T21:46:18.090039Z" + } }, - "outputs": [], "source": [ - "assert value(m.fs.operating_cost) == pytest.approx(312786.338, abs=1e-3)\n", + "assert value(m.fs.operating_cost) == pytest.approx(318024.909, abs=1e-3)\n", "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 80 }, { "cell_type": "markdown", @@ -1548,49 +3324,88 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" - ] + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 763.507 K\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 81 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:19.262061Z", + "start_time": "2025-11-20T21:46:18.121920Z" + } }, - "outputs": [], "source": [ "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", - "assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(696.112, abs=1e-3)\n", - "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.878, abs=1e-3)\n", + "print(value(m.fs.R101.outlet.temperature[0]))\n", + "assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(763.484, abs=1e-3)\n", + "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "763.5072359720118\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[82]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.H101.outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m500\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(value(m.fs.R101.outlet.temperature[\u001b[32m0\u001b[39m]))\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.R101.outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m763.484\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.F101.vap_outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m301.881\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.F102.vap_outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m362.935\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: " + ] + } + ], + "execution_count": 82 } ], "metadata": { @@ -1610,7 +3425,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py new file mode 100644 index 00000000..57eac3e4 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet.py @@ -0,0 +1,579 @@ +from pyomo.environ import ( + Constraint, + Var, + ConcreteModel, + Expression, + Objective, + TransformationFactory, + value, +) +from pyomo.network import Arc, SequentialDecomposition + +from idaes.core import FlowsheetBlock + +from idaes.models.unit_models import ( + PressureChanger, + Mixer, + Separator as Splitter, + Heater, + StoichiometricReactor, + Feed, + Product, +) + +from idaes.core.util.exceptions import InitializationError +import idaes.logger as idaeslog + +# Todo: import flash model from idaes.models.unit_models + +# Todo: import flash model from idaes.models.unit_models +from idaes.models.unit_models import Flash + +from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption +from idaes.core.util.model_statistics import degrees_of_freedom + +from idaes.core.solvers import get_solver + +from idaes.models.properties.modular_properties.base.generic_property import ( + GenericParameterBlock, +) +from idaes.models.properties.modular_properties.base.generic_reaction import ( + GenericReactionParameterBlock, +) +from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config +from idaes_examples.mod.hda.hda_reaction_modular import reaction_config + +m = ConcreteModel() +m.fs = FlowsheetBlock(dynamic=False) + +m.fs.thermo_params = GenericParameterBlock(**thermo_config) +m.fs.reaction_params = GenericReactionParameterBlock( + property_package=m.fs.thermo_params, **reaction_config +) + +m.fs.I101 = Feed(property_package=m.fs.thermo_params) +m.fs.I102 = Feed(property_package=m.fs.thermo_params) + +m.fs.M101 = Mixer( + property_package=m.fs.thermo_params, + num_inlets=3, +) + +m.fs.H101 = Heater( + property_package=m.fs.thermo_params, + has_pressure_change=False, + has_phase_equilibrium=True, +) + +m.fs.R101 = StoichiometricReactor( + property_package=m.fs.thermo_params, + reaction_package=m.fs.reaction_params, + has_heat_of_reaction=True, + has_heat_transfer=True, + has_pressure_change=False, +) + +m.fs.F101 = Flash( + property_package=m.fs.thermo_params, + has_heat_transfer=True, + has_pressure_change=True, +) + +m.fs.S101 = Splitter( + property_package=m.fs.thermo_params, + ideal_separation=False, + outlet_list=["purge", "recycle"], +) + +m.fs.C101 = PressureChanger( + property_package=m.fs.thermo_params, + compressor=True, + thermodynamic_assumption=ThermodynamicAssumption.isothermal, +) + +m.fs.F102 = Flash( + property_package=m.fs.thermo_params, + has_heat_transfer=True, + has_pressure_change=True, +) + +m.fs.P101 = Product(property_package=m.fs.thermo_params) +m.fs.P102 = Product(property_package=m.fs.thermo_params) +m.fs.P103 = Product(property_package=m.fs.thermo_params) + +m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1) +m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2) +m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet) +m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet) +m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet) +m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet) +m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet) +m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet) +m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3) +m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet) +m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet) +m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet) + +TransformationFactory("network.expand_arcs").apply_to(m) + +m.fs.purity = Expression( + expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + / ( + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] + + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "toluene" + ] + ) +) + +m.fs.cooling_cost = Expression( + expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0]) +) + +m.fs.heating_cost = Expression( + expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0] +) + +m.fs.operating_cost = Expression( + expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost)) +) + +assert degrees_of_freedom(m) == 29 + +F_liq_toluene = 0.30 +F_liq_non_zero = 1e-5 + +F_vap_I101 = F_liq_non_zero * 4 +F_liq_I101 = F_liq_toluene + F_liq_non_zero + +m.fs.I101.flow_mol_phase[0, "Vap"].fix(F_vap_I101) +m.fs.I101.flow_mol_phase[0, "Liq"].fix(F_liq_I101) +m.fs.I101.mole_frac_phase_comp[0, "Vap", "benzene"].fix(F_liq_non_zero / F_vap_I101) +m.fs.I101.mole_frac_phase_comp[0, "Vap", "toluene"].fix(F_liq_non_zero / F_vap_I101) +m.fs.I101.mole_frac_phase_comp[0, "Vap", "hydrogen"].fix(F_liq_non_zero / F_vap_I101) +m.fs.I101.mole_frac_phase_comp[0, "Vap", "methane"].fix(F_liq_non_zero / F_vap_I101) +m.fs.I101.mole_frac_phase_comp[0, "Liq", "benzene"].fix(F_liq_non_zero / F_liq_I101) +m.fs.I101.mole_frac_phase_comp[0, "Liq", "toluene"].fix(F_liq_toluene / F_liq_I101) +m.fs.I101.temperature.fix(303.2) +m.fs.I101.pressure.fix(350000) + +F_vap_hydrogen = 0.30 +F_vap_methane = 0.020 + +F_vap_non_zero = 1e-5 +F_liq_non_zero = F_vap_non_zero + +F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero +F_liq_I102 = 2 * F_vap_non_zero + +m.fs.I102.flow_mol_phase[0, "Vap"].fix(F_vap_I102) +m.fs.I102.flow_mol_phase[0, "Liq"].fix(F_liq_I102) +m.fs.I102.mole_frac_phase_comp[0, "Vap", "benzene"].fix(F_vap_non_zero / F_vap_I102) +m.fs.I102.mole_frac_phase_comp[0, "Vap", "toluene"].fix(F_vap_non_zero / F_vap_I102) +m.fs.I102.mole_frac_phase_comp[0, "Vap", "hydrogen"].fix(F_vap_hydrogen / F_vap_I102) +m.fs.I102.mole_frac_phase_comp[0, "Vap", "methane"].fix(F_vap_methane / F_vap_I102) +m.fs.I102.mole_frac_phase_comp[0, "Liq", "benzene"].fix(F_liq_non_zero / F_liq_I102) +m.fs.I102.mole_frac_phase_comp[0, "Liq", "toluene"].fix(F_liq_non_zero / F_liq_I102) + +m.fs.I102.temperature.fix(303.2) +m.fs.I102.pressure.fix(350000) + +m.fs.H101.outlet.temperature.fix(600) + +m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1)) + +m.fs.R101.conv_constraint = Constraint( + expr=m.fs.R101.conversion + * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"]) + == ( + m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp["Vap", "toluene"] + - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "toluene" + ] + ) +) + +m.fs.R101.conversion.fix(0.75) +m.fs.R101.heat_duty.fix(0) + +m.fs.F101.vap_outlet.temperature.fix(325.0) +m.fs.F101.deltaP.fix(0) + +m.fs.F102.vap_outlet.temperature.fix(375) +m.fs.F102.deltaP.fix(-200000) + +m.fs.S101.split_fraction[0, "purge"].fix(0.2) +m.fs.C101.outlet.pressure.fix(350000) + +seq = SequentialDecomposition() +seq.options.select_tear_method = "heuristic" +seq.options.tear_method = "Wegstein" +seq.options.iterLim = 3 + +# Using the SD tool +G = seq.create_graph(m) +heuristic_tear_set = seq.tear_set_arcs(G, method="heuristic") +order = seq.calculation_order(G) + +for o in heuristic_tear_set: + print(o.name) + +for o in order: + print(o[0].name) + +tear_guesses = { + "flow_mol_phase": { + (0, "Liq"): F_liq_I101, + (0, "Vap"): F_vap_I102, + }, + "mole_frac_phase_comp": { + (0, "Liq", "benzene"): 1e-5 / F_liq_I101, + (0, "Liq", "toluene"): 0.30 / F_liq_I101, + (0, "Vap", "benzene"): 1e-5 / F_vap_I102, + (0, "Vap", "toluene"): 1e-5 / F_vap_I102, + (0, "Vap", "methane"): 0.02 / F_vap_I102, + (0, "Vap", "hydrogen"): 0.30 / F_vap_I102, + }, + "temperature": {0: 303}, + "pressure": {0: 350000}, +} + +# Pass the tear_guess to the SD tool +seq.set_guesses_for(m.fs.H101.inlet, tear_guesses) + + +def function(unit): + try: + initializer = unit.default_initializer() + initializer.initialize(unit, output_level=idaeslog.INFO) + except InitializationError: + solver = get_solver() + solver.solve(unit) + + +seq.run(m, function) + +# from idaes.core.util.initialization import propagate_state +# +# print(f"The DOF is {degrees_of_freedom(m)} initially") +# m.fs.s03_expanded.deactivate() +# print(f"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream") +# +# tear_guesses = { +# "flow_mol_phase": { +# (0, "Liq"): F_liq_I101, +# (0, "Vap"): F_vap_I102, +# +# }, +# "mole_frac_phase_comp": { +# (0, "Liq", "benzene"): 1e-5 / F_liq_I101, +# (0, "Liq", "toluene"): 0.30 / F_liq_I101, +# (0, "Vap", "benzene"): 1e-5 / F_vap_I102, +# (0, "Vap", "toluene"): 1e-5 / F_vap_I102, +# (0, "Vap", "methane"): 0.02 / F_vap_I102, +# (0, "Vap", "hydrogen"): 0.30 / F_vap_I102, +# }, +# "temperature": {0: 303}, +# "pressure": {0: 350000}, +# } +# +# for k, v in tear_guesses.items(): +# for k1, v1 in v.items(): +# getattr(m.fs.s03.destination, k)[k1].fix(v1) +# +# DOF_initial = degrees_of_freedom(m) +# +# print(f"The DOF is {degrees_of_freedom(m)} after setting the tear stream") +# +# m.fs.H101.default_initializer().initialize(m.fs.H101) +# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor +# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor +# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit +# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit +# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter +# propagate_state(m.fs.s07) +# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter +# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor +# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor +# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer +# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet +# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer +# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet +# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer +# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer +# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater +# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit +# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product +# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product +# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product + +optarg = { + "nlp_scaling_method": "user-scaling", + "OF_ma57_automatic_scaling": "yes", + "max_iter": 300, + "tol": 1e-8, +} +solver = get_solver("ipopt_v2", options=optarg) +results = solver.solve(m, tee=True) + +for k, v in tear_guesses.items(): + for k1, v1 in v.items(): + getattr(m.fs.H101.inlet, k)[k1].unfix() + +m.fs.s03_expanded.activate() +print( + f"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream" +) +# %% md +# ## 6 Solving the Model +# %% md +# We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html +# %% +optarg = { + "nlp_scaling_method": "user-scaling", + "OF_ma57_automatic_scaling": "yes", + "max_iter": 1000, + "tol": 1e-8, +} +# %% md +#
    +# Inline Exercise: +# Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following: +# +# solver = get_solver(solver_options=optarg)
    +# results = solver.solve(m, tee=True) +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
    +# +# %% +# Create the solver object + +# Solve the model +# %% +# Create the solver object +solver = get_solver("ipopt_v2", options=optarg) + +# Solve the model +results = solver.solve(m, tee=False) + +print(f"Solver result: {results}") +# %% +# Check solver solve status +from pyomo.environ import TerminationCondition + +assert results.solver.termination_condition == TerminationCondition.optimal +# %% md +# ## 7 Analyze the results +# +# +# +# %% md +# If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window. +# +# %% +# m.fs.visualize("HDA-Flowsheet") +# %% md +# Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display. +# %% +m.fs.report() +# %% md +# What is the total operating cost? +# %% +print("operating cost = $", value(m.fs.operating_cost)) +# %% +import pytest + +# assert value(m.fs.operating_cost) == pytest.approx(424513.9645, abs=1e-3) +# %% md +# For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method. +# %% +m.fs.F102.report() + +print() +print("benzene purity = ", value(m.fs.purity)) +# %% +assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3) +assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.03097, abs=1e-3) +assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3) +# %% md +# Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101. +# %% +from idaes.core.util.tables import ( + create_stream_table_dataframe, + stream_table_dataframe_to_string, +) + +st = create_stream_table_dataframe({"Reactor": m.fs.s05, "Light Gases": m.fs.s06}) +print(stream_table_dataframe_to_string(st)) +# %% md +# ## 8 Optimization +# +# +# We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\%. However, we are losing around 42\% of benzene in F101 vapor outlet stream. +# +# Let us try to minimize this cost such that: +# - we are producing at least 0.15 mol/s of benzene in F102 vapor outlet i.e. our product stream +# - purity of benzene i.e. the mole fraction of benzene in F102 vapor outlet is at least 80% +# - restricting the benzene loss in F101 vapor outlet to less than 20% +# +# For this problem, our decision variables are as follows: +# - H101 outlet temperature +# - R101 cooling duty provided +# - F101 outlet temperature +# - F102 outlet temperature +# - F102 deltaP in the flash tank +# +# %% md +# Let us declare our objective function for this problem. +# %% +m.fs.objective = Objective(expr=m.fs.operating_cost) +# %% md +# Now, we need to unfix the decision variables as we had solved a square problem (degrees of freedom = 0) until now. +# %% +m.fs.H101.outlet.temperature.unfix() +m.fs.R101.heat_duty.unfix() +m.fs.F101.vap_outlet.temperature.unfix() +m.fs.F102.vap_outlet.temperature.unfix() +# %% md +#
    +# Inline Exercise: +# Let us now unfix the remaining variable which is F102 pressure drop (F102.deltaP) +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
    +# +# +# %% +# Todo: Unfix deltaP for F102 +# %% +# Todo: Unfix deltaP for F102 +m.fs.F102.deltaP.unfix() +# %% +assert degrees_of_freedom(m) == 5 +# %% md +# Next, we need to set bounds on these decision variables to values shown below: +# +# - H101 outlet temperature [500, 600] K +# - R101 outlet temperature [600, 800] K +# - F101 outlet temperature [298, 450] K +# - F102 outlet temperature [298, 450] K +# - F102 outlet pressure [105000, 110000] Pa +# +# Let us first set the variable bound for the H101 outlet temperature as shown below: +# %% +m.fs.H101.outlet.temperature[0].setlb(500) +m.fs.H101.outlet.temperature[0].setub(600) +# %% md +#
    +# Inline Exercise: +# Now, set the variable bound for the R101 outlet temperature. +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
    +# %% +# Todo: Set the bounds for reactor outlet temperature +# %% +# Todo: Set the bounds for reactor outlet temperature +m.fs.R101.outlet.temperature[0].setlb(600) +m.fs.R101.outlet.temperature[0].setub(800) +# %% md +# Let us fix the bounds for the rest of the decision variables. +# %% +m.fs.F101.vap_outlet.temperature[0].setlb(298.0) +m.fs.F101.vap_outlet.temperature[0].setub(450.0) +m.fs.F102.vap_outlet.temperature[0].setlb(298.0) +m.fs.F102.vap_outlet.temperature[0].setub(450.0) +m.fs.F102.vap_outlet.pressure[0].setlb(105000) +m.fs.F102.vap_outlet.pressure[0].setub(110000) +# %% md +# Now, the only things left to define are our constraints on overhead loss in F101, product flow rate and purity in F102. Let us first look at defining a constraint for the overhead loss in F101 where we are restricting the benzene leaving the vapor stream to less than 20 \% of the benzene available in the reactor outlet. +# %% +m.fs.overhead_loss = Constraint( + expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + <= 0.20 + * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp["Vap", "benzene"] +) +# %% md +#
    +# Inline Exercise: +# Now, add the constraint such that we are producing at least 0.15 mol/s of benzene in the product stream which is the vapor outlet of F102. Let us name this constraint as m.fs.product_flow. +# +# Use Shift+Enter to run the cell once you have typed in your code. +#
    +# %% +# Todo: Add minimum product flow constraint +# %% +# Todo: Add minimum product flow constraint +m.fs.product_flow = Constraint( + expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[ + "Vap", "benzene" + ] + >= 0.15 +) +# %% md +# Let us add the final constraint on product purity or the mole fraction of benzene in the product stream such that it is at least greater than 80%. +# %% +m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80) +# %% md +# +# We have now defined the optimization problem and we are now ready to solve this problem. +# +# +# +# %% +results = solver.solve(m, tee=True) +# %% +# Check for solver solve status +from pyomo.environ import TerminationCondition + +assert results.solver.termination_condition == TerminationCondition.optimal +# %% md +# ### 8.1 Optimization Results +# +# Display the results and product specifications +# %% +print("operating cost = $", value(m.fs.operating_cost)) + +print() +print("Product flow rate and purity in F102") + +m.fs.F102.report() + +print() +print("benzene purity = ", value(m.fs.purity)) + +print() +print("Overhead loss in F101") +m.fs.F101.report() +# %% + +assert value(m.fs.operating_cost) == pytest.approx(318024.909, abs=1e-3) +assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3) +# %% md +# Display optimal values for the decision variables +# %% +print( + f"""Optimal Values: + +H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K + +R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K + +F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K + +F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K +F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa +""" +) +# %% +assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3) +# assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(696.112, abs=1e-3) +assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(763.484, abs=1e-3) +assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3) +assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3) +assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2) diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb index 2d862e0d..22c9fbaa 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_doc.ipynb @@ -2,8 +2,12 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + }, "tags": [ "header", "hide-cell" @@ -13,7 +17,7 @@ "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
    \n", + "Maintainer: Tanner Polley
    \n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
    \n", + "     2 Building a Model
    \n", + "     3 Scaling the Model
    \n", + "     4 Specifying the Model
    \n", + "     5 Initializing the Model
    \n", + "     6 Solving the Model
    \n", + "     7 Analyzing and Visualizing the Results
    \n", + "     8 Optimizing the Model
    \n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,13 +114,18 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "outputs": [], "source": [ "from pyomo.environ import (\n", @@ -110,7 +134,6 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", @@ -121,19 +144,26 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "outputs": [], "source": [ "from idaes.core import FlowsheetBlock" @@ -141,8 +171,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "outputs": [], "source": [ "from idaes.models.unit_models import (\n", @@ -151,7 +186,11 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" ] }, { @@ -166,8 +205,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.963041Z", + "start_time": "2025-11-20T21:46:09.957319Z" + }, "tags": [ "solution" ] @@ -187,24 +230,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "outputs": [], "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" + "from idaes.core.solvers import get_solver" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -220,27 +266,43 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "outputs": [], "source": [ "m = ConcreteModel()\n", @@ -256,13 +318,18 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "outputs": [], "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" ] }, @@ -270,20 +337,29 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "outputs": [], "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -293,27 +369,14 @@ ")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
    \n", - "Inline Exercise:\n", - "Let us now add the StoichiometricReactor(assign the name R101) and pass the following arguments:\n", - "
      \n", - "
    • \"property_package\": m.fs.thermo_params
    • \n", - "
    • \"reaction_package\": m.fs.reaction_params
    • \n", - "
    • \"has_heat_of_reaction\": True
    • \n", - "
    • \"has_heat_transfer\": True
    • \n", - "
    • \"has_pressure_change\": False
    • \n", - "
    \n", - "
    " - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.145853Z", + "start_time": "2025-11-20T21:46:10.127921Z" + }, "tags": [ "solution" ] @@ -344,8 +407,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 12, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "outputs": [], "source": [ "m.fs.F101 = Flash(\n", @@ -359,13 +427,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 13, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "outputs": [], "source": [ "m.fs.S101 = Splitter(\n", @@ -392,38 +465,67 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 14, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, "outputs": [], "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "### 2.2 Connecting Unit Models using Arcs\n", "\n", - "![](HDA_flowsheet.png) \n", - "\n", - "
    \n", - "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
    \n", - "\n" + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "outputs": [], + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.254153Z", + "start_time": "2025-11-20T21:46:10.248481Z" + }, "tags": [ "solution" ] @@ -443,28 +545,61 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "outputs": [], "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "outputs": [], + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ] + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "We have now connected the unit model block using the arcs. However, each of these arcs link to ports on the two unit models that are connected. In this case, the ports consist of the state variables that need to be linked between the unit models. Pyomo provides a convenient method to write these equality constraints for us between two ports and this is done as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "outputs": [], "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" @@ -474,9 +609,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -490,15 +625,24 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 20, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "outputs": [], "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" ] @@ -512,8 +656,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 21, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "outputs": [], "source": [ "m.fs.cooling_cost = Expression(\n", @@ -536,8 +685,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 22, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "outputs": [], "source": [ "m.fs.heating_cost = Expression(\n", @@ -554,8 +708,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 23, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "outputs": [], "source": [ "m.fs.operating_cost = Expression(\n", @@ -567,16 +726,30 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 24, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], "source": [ "print(degrees_of_freedom(m))" ] @@ -585,25 +758,36 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 25, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "outputs": [], "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" ] }, { @@ -611,7 +795,7 @@ "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
      \n", "
    • FH2 = 0.30 mol/s
    • \n", "
    • FCH4 = 0.02 mol/s
    • \n", @@ -624,35 +808,55 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 26, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "outputs": [], "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "outputs": [], "source": [ "m.fs.H101.outlet.temperature.fix(600)" @@ -667,17 +871,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 28, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "outputs": [], "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", @@ -694,34 +906,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 29, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
      \n", - "Inline Exercise:\n", - "Set the conditions for Flash F102 to the following conditions:\n", - "
        \n", - "
      • T = 375 K
      • \n", - "
      • deltaP = -200000
      • \n", - "
      \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      " - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.482109Z", + "start_time": "2025-11-20T21:46:10.475567Z" + }, "tags": [ "solution" ] @@ -741,35 +946,40 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 31, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "outputs": [], "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
      \n", - "Inline Exercise:\n", - "We have now defined all the feed conditions and the inputs required for the unit models. The system should now have 0 degrees of freedom i.e. should be a square problem. Please check that the degrees of freedom is 0. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      " - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.535421Z", + "start_time": "2025-11-20T21:46:10.507798Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], "source": [ "print(degrees_of_freedom(m))" ] @@ -778,25 +988,40 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", + "\n", + "\n", + "\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", "\n", - "![](HDA_flowsheet.png) \n" + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 33, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "outputs": [], "source": [ "seq = SequentialDecomposition()\n", @@ -819,9 +1044,22 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 34, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" @@ -836,11 +1074,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + }, "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], "source": [ "for o in order:\n", " print(o[0].name)" @@ -855,25 +1110,32 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 36, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "outputs": [], "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -892,8 +1154,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 37, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "outputs": [], "source": [ "def function(unit):\n", @@ -914,42 +1181,2615 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: Loading a SolverResults object with a warning status into\n", + "model.name=\"fs.R101\";\n", + " - termination condition: infeasible\n", + " - message from solver: Ipopt 3.13.2\\x3a Converged to a locally infeasible\n", + " point. Problem may be infeasible.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:40 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:41 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "WARNING: Loading a SolverResults object with a warning status into\n", + "model.name=\"fs.R101\";\n", + " - termination condition: infeasible\n", + " - message from solver: Ipopt 3.13.2\\x3a Converged to a locally infeasible\n", + " point. Problem may be infeasible.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:42 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-25 12:36:43 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "source": [ + "seq.run(m, function)" + ] + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, "outputs": [], "source": [ - "seq.run(m, function)" + "from idaes.core.util.initialization import propagate_state" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
      \n", - "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", - "results = solver.solve(m, tee=True)\n", + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      \n", - "\n" + "We will first ensure that are current degrees of freedom is still zero" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "outputs": [], + "source": [ + "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "outputs": [], + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "outputs": [], + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "outputs": [], + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpoctkmbii\\unknown.14248.22376.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpoctkmbii\\unknown.14248.22376.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 155\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.74e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reallocating memory for MA57: lfact (10193)\n", + " 1r 0.0000000e+00 3.74e+03 9.99e+02 3.6 0.00e+00 - 0.00e+00 3.17e-07R 3\n", + " 2r 0.0000000e+00 6.21e+04 1.21e+03 3.6 3.74e+06 - 3.68e-03 3.56e-04f 1\n", + " 3r 0.0000000e+00 5.77e+04 1.09e+05 3.6 5.16e+05 - 9.43e-02 4.63e-03f 1\n", + " 4r 0.0000000e+00 5.24e+04 6.21e+04 3.6 3.34e+03 - 2.55e-01 9.98e-02f 1\n", + " 5r 0.0000000e+00 6.56e+04 1.25e+05 3.6 1.51e+02 - 6.91e-01 4.02e-01f 1\n", + " 6r 0.0000000e+00 4.50e+04 2.67e+04 3.6 3.07e+01 - 1.00e+00 7.13e-01f 1\n", + " 7r 0.0000000e+00 1.83e+04 7.35e+03 3.6 3.08e+01 - 1.00e+00 1.00e+00f 1\n", + " 8r 0.0000000e+00 3.31e+04 4.68e+03 2.9 3.73e+01 - 7.83e-01 8.25e-01f 1\n", + " 9r 0.0000000e+00 1.06e+04 6.58e+02 2.9 2.24e+01 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.29e+03 4.93e+02 2.9 2.70e+01 - 1.00e+00 1.00e+00h 1\n", + " 11r 0.0000000e+00 5.23e+04 5.25e+02 2.2 2.33e+01 - 9.63e-01 9.78e-01f 1\n", + " 12r 0.0000000e+00 7.01e+03 1.04e+02 2.2 2.10e+01 - 1.00e+00 1.00e+00f 1\n", + " 13r 0.0000000e+00 8.17e+02 1.95e+01 2.2 5.26e+00 - 1.00e+00 1.00e+00f 1\n", + " 14r 0.0000000e+00 5.65e+03 7.52e+02 1.5 1.79e+01 - 8.36e-01 9.57e-01f 1\n", + " 15r 0.0000000e+00 1.39e+04 5.80e+02 1.5 7.56e+01 - 7.87e-01 5.50e-01f 1\n", + " 16r 0.0000000e+00 1.86e+04 4.51e+02 1.5 1.21e+01 - 6.10e-01 1.00e+00f 1\n", + " 17r 0.0000000e+00 1.25e+04 2.51e+02 1.5 1.27e+01 - 7.28e-01 1.00e+00f 1\n", + " 18r 0.0000000e+00 8.69e+02 4.46e+01 1.5 9.42e+00 - 1.00e+00 1.00e+00h 1\n", + " 19r 0.0000000e+00 2.75e+02 1.30e+00 1.5 2.78e+00 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.71e+03 2.13e+02 0.8 1.88e+01 - 9.33e-01 9.68e-01f 1\n", + " 21r 0.0000000e+00 9.91e+01 1.22e+02 0.8 1.24e-01 2.0 1.00e+00 1.00e+00f 1\n", + " 22r 0.0000000e+00 2.87e+01 1.01e+03 0.8 4.55e-01 1.5 3.90e-01 9.98e-01H 1\n", + " 23r 0.0000000e+00 4.95e+02 1.46e+02 0.8 4.53e-01 1.0 1.00e+00 9.27e-01f 1\n", + " 24r 0.0000000e+00 4.75e+02 3.38e+02 0.8 4.95e-01 1.5 6.73e-01 8.53e-01f 1\n", + " 25r 0.0000000e+00 2.04e+02 7.82e+01 0.8 7.99e-02 2.8 1.00e+00 1.00e+00f 1\n", + " 26r 0.0000000e+00 2.86e+02 1.37e+02 0.8 9.62e-01 2.3 2.38e-01 2.31e-01f 1\n", + " 27r 0.0000000e+00 2.57e+02 7.76e+02 0.8 7.36e-01 1.8 4.15e-01 7.40e-02f 1\n", + " 28r 0.0000000e+00 2.55e+02 7.67e+02 0.8 3.59e+02 - 2.06e-02 8.24e-03f 2\n", + " 29r 0.0000000e+00 3.58e+02 5.95e+01 0.8 1.21e-01 1.4 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 8.66e+02 2.43e+02 0.8 6.93e+01 - 9.31e-01 4.48e-01f 2\n", + " 31r 0.0000000e+00 7.82e+02 2.67e+02 0.8 5.52e+00 0.9 8.90e-02 9.64e-02h 1\n", + " 32r 0.0000000e+00 6.93e+02 1.87e+02 0.8 2.84e+01 - 5.79e-02 1.48e-01h 1\n", + " 33r 0.0000000e+00 5.58e+02 1.23e+02 0.8 2.39e+01 - 2.97e-01 3.32e-01f 1\n", + " 34r 0.0000000e+00 4.53e+02 2.25e+02 0.8 1.58e+01 - 1.41e-01 2.10e-01f 1\n", + " 35r 0.0000000e+00 4.31e+02 1.86e+02 0.8 1.74e+01 - 2.72e-02 5.15e-02h 1\n", + " 36r 0.0000000e+00 4.28e+02 3.00e+02 0.8 4.39e+01 - 1.73e-03 5.76e-03h 1\n", + " 37r 0.0000000e+00 4.28e+02 2.99e+02 0.8 1.11e+03 - 2.19e-05 2.25e-04h 1\n", + " 38r 0.0000000e+00 4.28e+02 6.92e+02 0.8 2.39e+02 1.3 2.42e-03 1.96e-04f 1\n", + " 39r 0.0000000e+00 4.12e+02 1.12e+04 0.8 1.90e+01 - 7.18e-01 3.76e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 1.29e+02 2.87e+02 0.8 1.04e+01 - 1.00e+00 1.00e+00f 1\n", + " 41r 0.0000000e+00 4.97e+01 7.12e+02 0.8 5.85e+00 - 5.86e-01 6.18e-01h 1\n", + " 42r 0.0000000e+00 1.60e+00 1.99e+02 0.8 7.12e-01 0.8 1.00e+00 1.00e+00f 1\n", + " 43r 0.0000000e+00 2.18e+01 1.63e+02 0.1 6.04e+01 0.4 1.22e-02 7.09e-03f 1\n", + " 44r 0.0000000e+00 7.21e+03 1.05e+03 0.1 1.64e+02 - 1.83e-01 7.12e-01f 1\n", + " 45r 0.0000000e+00 6.31e+03 7.50e+02 0.1 5.95e+01 - 1.09e-01 1.68e-01f 1\n", + " 46r 0.0000000e+00 6.22e+03 1.41e+03 0.1 9.02e+01 - 8.19e-04 1.38e-02f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 47r 0.0000000e+00 6.22e+03 1.41e+03 0.1 1.27e+02 0.8 1.98e-03 9.14e-04h 1\n", + " 48r 0.0000000e+00 6.21e+03 1.57e+03 0.1 2.55e+02 0.3 1.66e-05 7.85e-04h 1\n", + " 49r 0.0000000e+00 6.18e+03 1.56e+03 0.1 2.15e+01 0.7 2.64e-03 4.99e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 6.18e+03 1.60e+03 0.1 1.55e+02 0.3 2.53e-05 2.61e-04h 1\n", + " 51r 0.0000000e+00 6.18e+03 1.67e+03 0.1 7.60e+01 1.6 1.06e-02 3.63e-04h 1\n", + " 52r 0.0000000e+00 5.80e+03 1.65e+03 0.1 2.59e+01 - 3.10e-02 6.80e-02f 1\n", + " 53r 0.0000000e+00 5.29e+03 1.04e+03 0.1 3.13e+01 - 8.78e-01 6.14e-01f 1\n", + " 54r 0.0000000e+00 2.06e+03 3.00e+02 0.1 3.76e+01 - 7.50e-01 1.00e+00h 1\n", + " 55r 0.0000000e+00 5.02e+01 1.17e+02 0.1 1.26e+01 - 1.00e+00 1.00e+00h 1\n", + " 56r 0.0000000e+00 4.11e+01 1.08e+02 0.1 4.23e+00 - 2.42e-01 1.84e-01h 1\n", + " 57r 0.0000000e+00 2.12e+01 5.27e+01 0.1 1.15e+00 - 7.37e-01 8.32e-01h 1\n", + " 58r 0.0000000e+00 4.74e+01 3.85e+01 0.1 1.60e+00 - 9.93e-01 1.00e+00f 1\n", + " 59r 0.0000000e+00 1.17e+01 3.25e+01 0.1 1.40e+00 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 1.21e+03 4.46e+01 -0.6 5.97e+01 - 7.60e-01 6.94e-01f 1\n", + " 61r 0.0000000e+00 1.54e+03 4.60e+00 -0.6 9.23e+01 - 1.00e+00 1.00e+00f 1\n", + " 62r 0.0000000e+00 1.21e+01 9.28e+00 -0.6 4.59e+01 - 1.00e+00 1.00e+00h 1\n", + " 63r 0.0000000e+00 1.83e+00 9.35e-02 -0.6 2.84e+00 - 1.00e+00 1.00e+00h 1\n", + " 64r 0.0000000e+00 1.11e+03 6.94e+01 -1.3 7.51e+01 - 9.02e-01 9.81e-01f 1\n", + " 65r 0.0000000e+00 7.93e+00 9.52e-01 -1.3 2.38e+01 - 1.00e+00 1.00e+00h 1\n", + " 66r 0.0000000e+00 1.78e+00 1.07e-01 -1.3 8.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 67r 0.0000000e+00 2.18e-01 1.01e-05 -1.3 3.94e-03 - 1.00e+00 1.00e+00h 1\n", + " 68r 0.0000000e+00 1.15e+03 4.78e+01 -4.5 7.86e+01 - 7.94e-01 8.05e-01f 1\n", + " 69r 0.0000000e+00 5.20e+02 1.43e+02 -4.5 2.20e+01 - 9.21e-01 5.55e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 2.62e+02 4.30e+02 -4.5 1.21e-02 1.1 9.09e-01 4.96e-01h 1\n", + " 71r 0.0000000e+00 6.29e+01 1.51e+02 -4.5 1.25e-02 0.6 9.00e-01 7.60e-01h 1\n", + " 72r 0.0000000e+00 9.72e+00 5.07e+01 -4.5 5.71e-02 0.2 9.11e-01 8.46e-01h 1\n", + " 73r 0.0000000e+00 2.40e-01 8.98e-01 -4.5 1.58e-01 -0.3 1.00e+00 9.91e-01h 1\n", + " 74r 0.0000000e+00 3.60e-01 1.74e+02 -4.5 3.96e+03 - 6.95e-03 2.59e-03f 1\n", + " 75r 0.0000000e+00 8.17e-01 3.02e+02 -4.5 9.81e+00 - 7.96e-02 1.55e-02h 1\n", + " 76r 0.0000000e+00 2.96e+02 1.34e+03 -4.5 3.56e+00 - 9.74e-02 3.29e-01h 1\n", + " 77r 0.0000000e+00 2.24e+02 1.38e+03 -4.5 2.48e-02 -0.8 1.00e+00 2.45e-01h 1\n", + " 78r 0.0000000e+00 1.29e+03 6.57e+02 -4.5 1.82e+00 - 6.97e-01 1.00e+00h 1\n", + " 79r 0.0000000e+00 2.01e+02 1.01e+02 -4.5 2.12e+00 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 4.78e+00 7.47e-01 -4.5 3.32e-01 - 1.00e+00 1.00e+00h 1\n", + " 81r 0.0000000e+00 2.94e+00 2.75e-02 -4.5 2.59e-01 - 1.00e+00 1.00e+00h 1\n", + " 82r 0.0000000e+00 2.79e-01 2.57e-03 -4.5 2.99e-02 - 1.00e+00 1.00e+00h 1\n", + " 83r 0.0000000e+00 2.79e-01 4.06e-04 -4.5 4.57e-03 - 1.00e+00 1.00e+00h 1\n", + " 84r 0.0000000e+00 2.79e-01 1.25e-07 -4.5 8.34e-05 - 1.00e+00 1.00e+00h 1\n", + " 85r 0.0000000e+00 5.26e+01 1.09e+01 -6.8 7.12e-01 - 9.31e-01 8.92e-01f 1\n", + " 86r 0.0000000e+00 2.95e+01 4.47e+02 -6.8 1.59e-01 - 7.12e-01 4.40e-01h 1\n", + " 87r 0.0000000e+00 7.70e+00 1.01e+02 -6.8 9.53e-02 - 8.78e-01 7.65e-01h 1\n", + " 88r 0.0000000e+00 3.45e+00 1.42e+02 -6.8 9.16e-02 - 1.00e+00 7.55e-01h 1\n", + " 89r 0.0000000e+00 9.20e-01 4.87e+01 -6.8 1.08e-01 - 8.60e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 8.31e-01 1.80e-01 -6.8 1.38e-01 - 1.00e+00 1.00e+00h 1\n", + " 91r 0.0000000e+00 2.83e-01 1.84e-01 -6.8 7.34e-02 - 1.00e+00 1.00e+00h 1\n", + " 92r 0.0000000e+00 2.83e-01 4.21e+02 -6.8 9.27e-01 - 1.19e-01 4.48e-03h 6\n", + " 93r 0.0000000e+00 2.83e-01 1.51e+02 -6.8 9.89e-06 -1.3 1.00e+00 1.03e-01h 1\n", + " 94r 0.0000000e+00 2.83e-01 3.45e+02 -6.8 1.02e+00 - 1.44e-01 2.36e-02h 3\n", + " 95r 0.0000000e+00 2.83e-01 2.09e+01 -6.8 6.98e-03 -1.7 3.75e-02 2.48e-02h 2\n", + " 96r 0.0000000e+00 2.83e-01 7.23e+00 -6.8 5.65e-04 -2.2 9.81e-01 1.00e+00h 1\n", + " 97r 0.0000000e+00 1.20e+01 2.06e+02 -6.8 1.57e+00 - 1.00e+00 3.33e-01h 2\n", + " 98r 0.0000000e+00 1.19e+01 2.37e+01 -6.8 1.56e-02 - 1.00e+00 5.65e-03h 8\n", + " 99r 0.0000000e+00 1.18e+01 2.23e+01 -6.8 1.79e-02 - 1.00e+00 7.81e-03h 8\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 1.18e+01 2.16e+01 -6.8 1.76e-02 - 1.00e+00 1.95e-03h 10\n", + " 101r 0.0000000e+00 1.18e+01 2.14e+01 -6.8 1.76e-02 - 1.00e+00 9.77e-04h 11\n", + " 102r 0.0000000e+00 1.18e+01 2.13e+01 -6.8 1.76e-02 - 1.00e+00 4.88e-04h 12\n", + " 103r 0.0000000e+00 2.90e-01 3.50e-04 -6.8 1.76e-02 - 1.00e+00 1.00e+00h 1\n", + " 104r 0.0000000e+00 7.03e+00 2.14e+02 -6.8 4.02e-01 - 5.84e-01 1.00e+00h 1\n", + " 105r 0.0000000e+00 2.96e-01 5.54e+01 -6.8 7.32e-02 - 2.26e-01 1.00e+00h 1\n", + " 106r 0.0000000e+00 2.96e-01 8.03e-05 -6.8 1.47e-04 -2.7 1.00e+00 1.00e+00h 1\n", + " 107r 0.0000000e+00 2.95e-01 4.46e+01 -6.8 1.04e-01 - 1.00e+00 5.00e-01h 2\n", + " 108r 0.0000000e+00 2.95e-01 1.34e-02 -6.8 1.91e-02 - 1.00e+00 1.00e+00h 1\n", + " 109r 0.0000000e+00 2.94e-01 1.41e-03 -6.8 3.97e-02 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 0.0000000e+00 2.94e-01 9.14e-04 -6.8 2.67e-02 - 1.00e+00 1.00e+00h 1\n", + " 111r 0.0000000e+00 2.94e-01 4.70e-05 -6.8 1.04e-03 - 1.00e+00 1.00e+00h 1\n", + " 112r 0.0000000e+00 2.94e-01 1.32e-07 -6.8 7.16e-04 - 1.00e+00 1.00e+00h 1\n", + " 113r 0.0000000e+00 2.94e-01 1.82e-12 -6.8 2.28e-06 - 1.00e+00 1.00e+00h 1\n", + " 114r 0.0000000e+00 9.46e-01 5.08e+00 -9.0 2.12e-01 - 6.64e-01 6.35e-01h 1\n", + " 115r 0.0000000e+00 1.29e+01 9.86e+00 -9.0 5.14e-01 - 7.92e-01 7.53e-01h 1\n", + " 116r 0.0000000e+00 6.76e+00 1.53e+02 -9.0 2.57e-01 - 8.31e-01 6.76e-01h 1\n", + " 117r 0.0000000e+00 8.96e+00 2.11e+00 -9.0 1.62e-01 - 1.00e+00 1.00e+00h 1\n", + " 118r 0.0000000e+00 8.94e-01 8.15e-01 -9.0 8.76e-02 - 1.00e+00 1.00e+00h 1\n", + " 119r 0.0000000e+00 5.50e-01 2.30e-02 -9.0 1.13e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 0.0000000e+00 2.99e-01 1.49e-04 -9.0 1.27e-02 - 1.00e+00 1.00e+00h 1\n", + " 121r 0.0000000e+00 2.98e-01 2.05e-05 -9.0 1.10e-02 - 1.00e+00 1.00e+00h 1\n", + " 122r 0.0000000e+00 2.98e-01 2.86e-08 -9.0 5.44e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 122\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 4.6276843335396955e-07 4.6276843335396955e-07\n", + "Constraint violation....: 2.9835465732216782e-01 2.9835465732216782e-01\n", + "Complementarity.........: 9.0909090909100423e-10 9.0909090909100423e-10\n", + "Overall NLP error.......: 2.9835465732216782e-01 2.9835465732216782e-01\n", + "\n", + "\n", + "Number of objective function evaluations = 193\n", + "Number of objective gradient evaluations = 3\n", + "Number of equality constraint evaluations = 193\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 125\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 123\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.161\n", + "Total CPU secs in NLP function evaluations = 0.016\n", + "\n", + "EXIT: Converged to a point of local infeasibility. Problem may be infeasible.\n" + ] + } + ], + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "outputs": [], + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.382669Z", + "start_time": "2025-11-20T21:46:17.293013Z" + }, "tags": [ "solution" ] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpg07cmjii\\unknown.14248.22376.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpg07cmjii\\unknown.14248.22376.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 155\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.74e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1r 0.0000000e+00 3.74e+03 9.99e+02 3.6 0.00e+00 - 0.00e+00 3.17e-07R 3\n", + " 2r 0.0000000e+00 6.21e+04 1.21e+03 3.6 3.74e+06 - 3.68e-03 3.56e-04f 1\n", + " 3r 0.0000000e+00 5.77e+04 1.01e+05 3.6 5.16e+05 - 8.85e-02 4.63e-03f 1\n", + " 4r 0.0000000e+00 5.27e+04 7.54e+04 3.6 3.55e+03 - 2.53e-01 9.39e-02f 1\n", + " 5r 0.0000000e+00 6.46e+04 1.25e+05 3.6 1.62e+02 - 6.86e-01 3.91e-01f 1\n", + " 6r 0.0000000e+00 4.60e+04 2.59e+04 3.6 3.07e+01 - 1.00e+00 7.29e-01f 1\n", + " 7r 0.0000000e+00 1.41e+04 8.03e+03 3.6 3.17e+01 - 1.00e+00 1.00e+00f 1\n", + " 8r 0.0000000e+00 3.34e+04 6.37e+03 2.9 3.71e+01 - 7.68e-01 8.25e-01f 1\n", + " 9r 0.0000000e+00 1.19e+04 7.40e+02 2.9 2.24e+01 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 0.0000000e+00 6.30e+03 4.59e+02 2.9 2.35e+01 - 1.00e+00 1.00e+00h 1\n", + " 11r 0.0000000e+00 5.23e+04 5.45e+02 2.2 2.33e+01 - 9.62e-01 9.77e-01f 1\n", + " 12r 0.0000000e+00 7.00e+03 1.04e+02 2.2 2.11e+01 - 1.00e+00 1.00e+00f 1\n", + " 13r 0.0000000e+00 7.13e+02 1.92e+01 2.2 5.17e+00 - 1.00e+00 1.00e+00f 1\n", + " 14r 0.0000000e+00 5.67e+03 7.52e+02 1.5 1.80e+01 - 8.36e-01 9.57e-01f 1\n", + " 15r 0.0000000e+00 1.39e+04 5.79e+02 1.5 7.56e+01 - 7.87e-01 5.50e-01f 1\n", + " 16r 0.0000000e+00 1.86e+04 4.46e+02 1.5 1.21e+01 - 6.13e-01 1.00e+00f 1\n", + " 17r 0.0000000e+00 1.24e+04 2.49e+02 1.5 1.26e+01 - 7.29e-01 1.00e+00f 1\n", + " 18r 0.0000000e+00 8.65e+02 4.42e+01 1.5 9.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 19r 0.0000000e+00 2.73e+02 1.31e+00 1.5 2.73e+00 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 0.0000000e+00 3.72e+03 2.13e+02 0.8 1.88e+01 - 9.33e-01 9.68e-01f 1\n", + " 21r 0.0000000e+00 9.91e+01 1.22e+02 0.8 1.24e-01 2.0 1.00e+00 1.00e+00f 1\n", + " 22r 0.0000000e+00 2.89e+01 1.01e+03 0.8 4.57e-01 1.5 3.88e-01 9.92e-01H 1\n", + " 23r 0.0000000e+00 4.92e+02 1.65e+02 0.8 4.52e-01 1.0 1.00e+00 9.06e-01f 1\n", + " 24r 0.0000000e+00 4.89e+02 3.27e+02 0.8 4.93e-01 1.5 6.74e-01 8.51e-01f 1\n", + " 25r 0.0000000e+00 2.08e+02 7.82e+01 0.8 7.90e-02 2.8 1.00e+00 1.00e+00f 1\n", + " 26r 0.0000000e+00 2.93e+02 1.41e+02 0.8 9.61e-01 2.3 2.45e-01 2.35e-01f 1\n", + " 27r 0.0000000e+00 2.70e+02 7.26e+02 0.8 8.43e-01 1.8 3.36e-01 6.18e-02f 1\n", + " 28r 0.0000000e+00 2.69e+02 7.21e+02 0.8 5.66e+02 - 1.20e-02 4.81e-03f 2\n", + " 29r 0.0000000e+00 4.15e+02 6.03e+01 0.8 1.17e-01 1.4 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30r 0.0000000e+00 8.56e+02 2.58e+02 0.8 7.00e+01 - 9.49e-01 4.42e-01f 2\n", + " 31r 0.0000000e+00 6.84e+02 2.86e+02 0.8 2.71e+00 0.9 1.79e-01 2.01e-01h 1\n", + " 32r 0.0000000e+00 5.92e+02 1.69e+02 0.8 2.88e+01 - 1.34e-01 3.24e-01f 1\n", + " 33r 0.0000000e+00 4.89e+02 1.45e+02 0.8 1.92e+01 - 1.00e+00 1.00e+00f 1\n", + " 34r 0.0000000e+00 7.71e+00 5.04e+01 0.8 1.11e+00 - 1.00e+00 1.00e+00h 1\n", + " 35r 0.0000000e+00 8.63e+03 3.42e+01 -0.6 2.52e+01 - 6.33e-01 6.26e-01f 1\n", + " 36r 0.0000000e+00 5.46e+03 5.26e+02 -0.6 1.02e+00 0.4 6.69e-01 3.70e-01f 1\n", + " 37r 0.0000000e+00 2.30e+03 1.84e+02 -0.6 6.65e-01 0.8 6.29e-01 5.80e-01f 1\n", + " 38r 0.0000000e+00 9.77e+02 7.18e+01 -0.6 1.85e+00 0.4 4.96e-01 6.05e-01f 1\n", + " 39r 0.0000000e+00 7.39e+02 5.97e+01 -0.6 2.45e+00 -0.1 4.52e-01 4.94e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40r 0.0000000e+00 8.88e+02 1.40e+02 -0.6 7.33e+00 -0.6 6.79e-01 3.09e-01h 1\n", + " 41r 0.0000000e+00 1.61e+01 1.29e+01 -0.6 3.68e-01 0.7 1.00e+00 1.00e+00h 1\n", + " 42r 0.0000000e+00 6.47e+01 6.22e+00 -0.6 9.57e-01 0.3 1.00e+00 1.00e+00h 1\n", + " 43r 0.0000000e+00 5.42e+02 5.88e+00 -0.6 3.02e+00 -0.2 1.00e+00 1.00e+00h 1\n", + " 44r 0.0000000e+00 1.31e+03 5.88e+01 -0.6 9.54e+00 -0.7 5.38e-01 4.31e-01h 1\n", + " 45r 0.0000000e+00 1.41e+03 2.73e+02 -0.6 1.19e+02 - 1.87e-01 1.21e-01h 1\n", + " 46r 0.0000000e+00 1.08e+03 3.24e+02 -0.6 1.37e+02 - 6.36e-01 4.65e-01f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 47r 0.0000000e+00 6.96e+02 2.77e+02 -0.6 8.41e+00 - 4.25e-01 3.72e-01h 1\n", + " 48r 0.0000000e+00 1.45e+02 1.84e+02 -0.6 8.64e+00 - 5.45e-01 7.92e-01h 1\n", + " 49r 0.0000000e+00 7.13e+01 3.91e+02 -0.6 2.50e+00 - 7.16e-01 5.13e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50r 0.0000000e+00 4.36e+00 1.14e+02 -0.6 2.79e+00 - 1.00e+00 1.00e+00f 1\n", + " 51r 0.0000000e+00 6.03e-01 2.36e+01 -0.6 8.61e-01 - 1.00e+00 1.00e+00h 1\n", + " 52r 0.0000000e+00 6.61e-01 4.55e+00 -0.6 2.56e-01 - 1.00e+00 1.00e+00h 1\n", + " 53r 0.0000000e+00 1.10e+03 6.90e+01 -1.3 7.52e+01 - 9.02e-01 9.81e-01f 1\n", + " 54r 0.0000000e+00 8.00e+00 8.01e-01 -1.3 2.37e+01 - 1.00e+00 1.00e+00h 1\n", + " 55r 0.0000000e+00 1.78e+00 1.07e-01 -1.3 8.16e-01 - 1.00e+00 1.00e+00h 1\n", + " 56r 0.0000000e+00 2.18e-01 5.40e-06 -1.3 3.90e-03 - 1.00e+00 1.00e+00h 1\n", + " 57r 0.0000000e+00 1.15e+03 4.77e+01 -4.5 7.87e+01 - 7.94e-01 8.05e-01f 1\n", + " 58r 0.0000000e+00 5.17e+02 1.43e+02 -4.5 2.20e+01 - 9.21e-01 5.56e-01h 1\n", + " 59r 0.0000000e+00 2.84e+02 5.22e+02 -4.5 1.42e-01 -1.2 9.08e-01 4.51e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60r 0.0000000e+00 5.10e+01 1.24e+02 -4.5 2.35e-01 -1.6 9.14e-01 8.21e-01h 1\n", + " 61r 0.0000000e+00 5.05e+01 4.54e+02 -4.5 4.49e+02 - 1.00e+00 2.18e-02h 1\n", + " 62r 0.0000000e+00 1.39e+03 2.01e+02 -4.5 3.30e+00 - 1.00e+00 9.24e-01h 1\n", + " 63r 0.0000000e+00 2.91e+02 7.48e+01 -4.5 1.78e-01 - 1.00e+00 7.97e-01h 1\n", + " 64r 0.0000000e+00 4.07e+00 2.17e+01 -4.5 7.87e-02 - 1.00e+00 1.00e+00h 1\n", + " 65r 0.0000000e+00 3.04e+00 2.05e+02 -4.5 5.95e-01 - 1.00e+00 2.50e-01h 3\n", + " 66r 0.0000000e+00 2.27e+00 1.18e+02 -4.5 5.27e-01 - 1.00e+00 2.50e-01h 3\n", + " 67r 0.0000000e+00 2.00e+00 6.21e+01 -4.5 3.35e-01 - 1.00e+00 5.00e-01h 2\n", + " 68r 0.0000000e+00 9.09e-01 8.92e-02 -4.5 1.44e-01 - 1.00e+00 1.00e+00h 1\n", + " 69r 0.0000000e+00 2.78e-01 2.22e-02 -4.5 6.01e-02 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70r 0.0000000e+00 2.78e-01 9.38e-05 -4.5 1.31e-03 - 1.00e+00 1.00e+00h 1\n", + " 71r 0.0000000e+00 5.15e+01 1.10e+01 -6.8 7.08e-01 - 9.31e-01 8.92e-01h 1\n", + " 72r 0.0000000e+00 2.90e+01 4.50e+02 -6.8 1.50e-01 - 7.13e-01 4.39e-01h 1\n", + " 73r 0.0000000e+00 7.89e+00 1.01e+02 -6.8 8.85e-02 - 8.77e-01 7.65e-01h 1\n", + " 74r 0.0000000e+00 2.97e+00 1.42e+02 -6.8 9.08e-02 - 1.00e+00 7.58e-01h 1\n", + " 75r 0.0000000e+00 8.82e-01 4.89e+01 -6.8 1.11e-01 - 8.59e-01 1.00e+00h 1\n", + " 76r 0.0000000e+00 7.58e-01 1.53e-01 -6.8 1.32e-01 - 1.00e+00 1.00e+00h 1\n", + " 77r 0.0000000e+00 2.82e-01 2.05e-01 -6.8 7.96e-02 - 1.00e+00 1.00e+00h 1\n", + " 78r 0.0000000e+00 2.82e-01 6.98e+01 -6.8 5.00e-01 - 2.24e-01 2.59e-01H 1\n", + " 79r 0.0000000e+00 2.82e-01 2.94e+02 -6.8 1.59e-01 - 1.00e+00 1.67e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 0.0000000e+00 2.81e-01 1.89e+02 -6.8 4.85e-01 - 8.32e-02 9.31e-02f 2\n", + " 81r 0.0000000e+00 2.81e-01 5.14e+02 -6.8 7.87e-04 -2.1 4.98e-01 7.44e-01h 1\n", + " 82r 0.0000000e+00 2.81e-01 9.19e+02 -6.8 2.22e-04 -2.6 1.00e+00 2.63e-01h 1\n", + " 83r 0.0000000e+00 2.81e-01 1.65e-02 -6.8 9.95e-04 -3.1 1.00e+00 1.00e+00f 1\n", + " 84r 0.0000000e+00 7.23e+00 1.63e-01 -6.8 4.06e-01 - 1.00e+00 1.00e+00h 1\n", + " 85r 0.0000000e+00 2.87e-01 2.33e-04 -6.8 9.28e-03 - 1.00e+00 1.00e+00h 1\n", + " 86r 0.0000000e+00 2.87e-01 1.97e+00 -6.8 5.56e-01 - 1.00e+00 1.22e-04h 14\n", + " 87r 0.0000000e+00 2.87e-01 2.46e+00 -6.8 5.00e-01 - 1.00e+00 1.22e-04h 14\n", + " 88r 0.0000000e+00 2.87e-01 2.58e+00 -6.8 4.78e-01 - 1.00e+00 1.22e-04h 14\n", + " 89r 0.0000000e+00 2.87e-01 2.62e+00 -6.8 4.70e-01 - 1.00e+00 1.22e-04h 14\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.67e-01 - 1.00e+00 1.22e-04h 14\n", + " 91r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.66e-01 - 1.00e+00 1.22e-04h 14\n", + " 92r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.65e-01 - 1.00e+00 1.22e-04h 14\n", + " 93r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.65e-01 - 1.00e+00 1.22e-04h 14\n", + " 94r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.65e-01 - 1.00e+00 1.22e-04h 14\n", + " 95r 0.0000000e+00 2.87e-01 2.64e+00 -6.8 4.65e-01 - 1.00e+00 1.22e-04h 14\n", + " 96r 0.0000000e+00 9.42e+00 1.88e-02 -6.8 4.65e-01 - 1.00e+00 1.00e+00w 1\n", + " 97r 0.0000000e+00 2.93e-01 1.19e-06 -6.8 8.82e-04 - 1.00e+00 1.00e+00w 1\n", + " 98r 0.0000000e+00 2.93e-01 5.78e-06 -6.8 2.07e-03 - 1.00e+00 1.00e+00w 1\n", + " 99r 0.0000000e+00 2.93e-01 2.04e-11 -6.8 4.54e-06 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 0.0000000e+00 7.74e-01 4.78e+00 -9.0 2.09e-01 - 6.64e-01 6.37e-01h 1\n", + " 101r 0.0000000e+00 8.46e+00 3.40e+01 -9.0 3.17e-01 - 9.10e-01 7.63e-01h 1\n", + " 102r 0.0000000e+00 4.04e+00 2.19e+02 -9.0 2.21e-01 - 8.62e-01 6.33e-01h 1\n", + " 103r 0.0000000e+00 7.03e+00 1.45e+00 -9.0 1.41e-01 - 1.00e+00 1.00e+00h 1\n", + " 104r 0.0000000e+00 7.21e-01 5.48e-01 -9.0 9.46e-02 - 1.00e+00 1.00e+00h 1\n", + " 105r 0.0000000e+00 2.97e-01 1.72e-02 -9.0 7.60e-02 - 1.00e+00 1.00e+00h 1\n", + " 106r 0.0000000e+00 2.97e-01 6.61e-05 -9.0 2.35e-02 - 1.00e+00 1.00e+00h 1\n", + " 107r 0.0000000e+00 2.97e-01 1.83e-06 -9.0 1.21e-03 - 1.00e+00 1.00e+00h 1\n", + " 108r 0.0000000e+00 2.97e-01 3.43e-08 -9.0 2.97e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 108\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 3.0151134107357916e-07 3.0151134107357916e-07\n", + "Constraint violation....: 2.9731578903766509e-01 2.9731578903766509e-01\n", + "Complementarity.........: 9.0909090909099699e-10 9.0909090909099699e-10\n", + "Overall NLP error.......: 2.9731578903766509e-01 2.9731578903766509e-01\n", + "\n", + "\n", + "Number of objective function evaluations = 271\n", + "Number of objective gradient evaluations = 3\n", + "Number of equality constraint evaluations = 271\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 111\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 109\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.155\n", + "Total CPU secs in NLP function evaluations = 0.015\n", + "\n", + "EXIT: Converged to a point of local infeasibility. Problem may be infeasible.\n" + ] + } + ], "source": [ "# Create the solver object\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=True)" @@ -959,17 +3799,88 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", + "## 7 Analyze the results\n", "\n", - "\n", - "What is the total operating cost? " + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate Liq mole / second 0.30001 2.0000e-05 0.29609 4.7359e-12 0.22506 1.0000e-08 0.30007 8.0134e-09 8.0151e-09 1.0000e-08 0.30007 2.0077e-09\n", + " Total Molar Flowrate Vap mole / second 4.0000e-05 0.32002 0.32272 0.61696 0.075008 2.0137e-10 1.0000e-08 1.5056e-10 1.3399e-10 1.9913e-08 1.0000e-08 4.0429e-11\n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 3.3332e-05 0.50000 0.00012935 5.9851e-05 1.0000e-20 1.0000e-20 1.0000e-20 0.0016277 0.0017605 1.0000e-20 1.0000e-20 0.0038222\n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.99997 0.50000 0.99987 0.99994 1.0000 1.0000 1.0000 0.99837 0.99824 1.0000 1.0000 0.99618\n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.25000 3.1248e-05 5.2698e-06 6.4834e-05 1.0000e-20 1.0000e-20 1.0000e-20 0.00017956 0.00019422 1.0000e-20 1.0000e-20 0.00042167\n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.25000 3.1248e-05 0.012327 0.48630 1.0000 0.037785 0.037785 0.037723 0.037718 0.51680 0.51680 0.037640\n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.25000 0.93744 0.92592 0.48184 1.3527e-09 0.49388 0.49388 0.49395 0.49398 0.24801 0.24801 0.49387\n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.25000 0.062496 0.061748 0.031794 1.2842e-09 0.46834 0.46834 0.46815 0.46810 0.23519 0.23519 0.46807\n", + " Temperature kelvin 303.20 303.20 300.45 600.00 664.03 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "source": [ + "m.fs.report()" + ] + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], + "source": [ + "What is the total operating cost?" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 225939.23444372677\n" + ] + } + ], "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))" ] @@ -978,14 +3889,64 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 50, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 2575.4 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.30007 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 1.0000e-20 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 1.0000 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 1.0000e-20 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.037785 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.49388 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.46834 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.30007 \n", + " flow_mol_phase Vap mole / second - 1.9913e-08 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 1.0000e-20 1.0000e-20 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 1.0000 1.0000 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 1.0000e-20 1.0000e-20 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.51680 0.51680 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.24801 0.24801 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.23519 0.23519 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 1.934999854274726e-20\n" + ] + } + ], "source": [ "m.fs.F102.report()\n", "\n", @@ -997,19 +3958,37 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
      \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
      \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 51, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate Liq mole / second 0.22506 1.0000e-08 \n", + "Total Molar Flowrate Vap mole / second 0.075008 2.0137e-10 \n", + "Total Mole Fraction ('Liq', 'benzene') dimensionless 1.0000e-20 1.0000e-20 \n", + "Total Mole Fraction ('Liq', 'toluene') dimensionless 1.0000 1.0000 \n", + "Total Mole Fraction ('Vap', 'benzene') dimensionless 1.0000e-20 1.0000e-20 \n", + "Total Mole Fraction ('Vap', 'toluene') dimensionless 1.0000 0.037785 \n", + "Total Mole Fraction ('Vap', 'hydrogen') dimensionless 1.3527e-09 0.49388 \n", + "Total Mole Fraction ('Vap', 'methane') dimensionless 1.2842e-09 0.46834 \n", + "Temperature kelvin 664.03 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1024,19 +4003,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
      \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      \n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1063,8 +4030,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 52, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "outputs": [], "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" @@ -1079,8 +4051,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 53, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "outputs": [], "source": [ "m.fs.H101.outlet.temperature.unfix()\n", @@ -1089,23 +4066,14 @@ "m.fs.F102.vap_outlet.temperature.unfix()" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
      \n", - "Inline Exercise:\n", - "Let us now unfix the remaining variable which is F102 pressure drop (F102.deltaP) \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      \n", - "\n" - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.720592Z", + "start_time": "2025-11-20T21:46:17.717532Z" + }, "tags": [ "solution" ] @@ -1133,30 +4101,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 55, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "outputs": [], "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
      \n", - "Inline Exercise:\n", - "Now, set the variable bound for the R101 outlet temperature.\n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      " - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.812504Z", + "start_time": "2025-11-20T21:46:17.807564Z" + }, "tags": [ "solution" ] @@ -1177,8 +4142,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 57, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "outputs": [], "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", @@ -1198,32 +4168,32 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 58, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "outputs": [], "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
      \n", - "Inline Exercise:\n", - "Now, add the constraint such that we are producing at least 0.15 mol/s of benzene in the product stream which is the vapor outlet of F102. Let us name this constraint as m.fs.product_flow. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
      " - ] - }, { "cell_type": "code", - "execution_count": null, + "execution_count": 59, "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.876414Z", + "start_time": "2025-11-20T21:46:17.872250Z" + }, "tags": [ "solution" ] @@ -1232,7 +4202,10 @@ "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] >= 0.15\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", ")" ] }, @@ -1245,8 +4218,13 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 60, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "outputs": [], "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" @@ -1264,9 +4242,578 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 61, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpl0wqmn_f\\unknown.14248.22376.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpl0wqmn_f\\unknown.14248.22376.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 159\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 2.2593923e+05 4.10e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 2.2592658e+05 4.10e+04 6.94e+00 -1.0 2.26e+06 - 1.24e-06 1.27e-06f 1\n", + " 2 2.2592558e+05 4.10e+04 3.83e+02 -1.0 1.09e+07 - 2.51e-06 1.27e-08f 1\n", + " 3 2.2575143e+05 4.10e+04 9.02e+03 -1.0 2.27e+09 - 2.63e-07 1.12e-08f 1\n", + " 4 2.1959194e+05 4.10e+04 5.77e+03 -1.0 2.25e+09 - 2.72e-07 3.98e-07f 1\n", + " 5 1.8296150e+05 3.46e+05 1.20e+05 -1.0 1.14e+09 - 7.70e-07 4.70e-06f 1\n", + " 6 1.8296150e+05 3.45e+05 4.95e+07 -1.0 1.99e+04 6.0 1.10e-01 2.49e-03h 1\n", + " 7 1.8308684e+05 3.45e+05 1.07e+10 -1.0 1.59e+07 - 4.38e-11 2.97e-05h 1\n", + " 8 1.8308686e+05 3.45e+05 1.07e+10 -1.0 3.47e+04 5.5 2.57e-08 1.27e-06f 2\n", + " 9 1.8308346e+05 3.45e+05 1.07e+10 -1.0 2.33e+06 - 1.28e-06 1.28e-06f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10r 1.8308346e+05 3.45e+05 9.99e+02 5.5 0.00e+00 - 0.00e+00 6.41e-09R 2\n", + " 11r 1.8308366e+05 3.44e+05 6.06e+03 5.5 3.59e+08 - 9.52e-05 2.75e-06f 1\n", + " 12r 1.8308341e+05 3.96e+04 6.44e+03 3.4 3.13e+08 - 4.75e-04 1.01e-03f 1\n", + " 13 1.8245986e+05 3.96e+04 3.21e+03 -1.0 9.17e+06 - 1.24e-04 1.01e-05f 1\n", + " 14 1.8245424e+05 3.96e+04 4.69e+06 -1.0 8.13e+06 - 1.38e-04 1.01e-07f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 15 1.8245406e+05 3.96e+04 8.01e+11 -1.0 5.70e+07 - 3.66e-04 1.06e-09f 2\n", + " 16 1.8163981e+05 3.96e+04 1.52e+12 -1.0 5.47e+08 - 2.78e-05 1.46e-05f 1\n", + " 17r 1.8163981e+05 3.96e+04 9.99e+02 4.6 0.00e+00 - 0.00e+00 1.32e-12R 2\n", + " 18r 1.8164024e+05 5.96e+04 6.63e+04 4.6 3.30e+07 - 1.77e-02 1.18e-04f 1\n", + " 19r 1.8164102e+05 4.78e+04 6.11e+04 3.2 1.72e+06 - 1.38e-01 1.86e-02f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20r 1.8164265e+05 4.73e+04 2.42e+04 3.2 2.06e+06 - 6.74e-01 1.03e-02f 1\n", + " 21r 1.8163776e+05 5.59e+04 1.44e+04 3.2 1.58e+03 - 4.29e-01 4.00e-01f 1\n", + " 22r 1.8168500e+05 4.59e+04 2.12e+03 3.2 6.14e+02 - 9.01e-01 8.37e-01f 1\n", + " 23r 1.8167353e+05 7.43e+04 2.27e+03 3.2 1.36e+02 - 3.19e-01 3.02e-01f 1\n", + " 24r 1.8153947e+05 5.07e+04 1.27e+04 3.2 6.53e+01 - 7.65e-01 1.00e+00f 1\n", + " 25r 1.8153947e+05 4.53e+04 1.69e+04 3.2 1.56e+01 4.0 1.07e-01 1.08e-01h 1\n", + " 26r 1.8153947e+05 2.41e+04 6.04e+04 3.2 1.81e+01 3.5 8.20e-01 1.00e+00f 1\n", + " 27 3.9962752e+04 2.41e+04 8.65e+01 -1.0 1.51e+07 - 1.07e-03 1.07e-03f 1\n", + " 28 1.7595823e+04 2.41e+04 1.10e+02 -1.0 2.01e+06 - 8.21e-03 1.19e-03f 1\n", + " 29 -1.6176446e+04 2.40e+04 4.65e+02 -1.0 1.41e+06 - 6.16e-03 4.06e-03f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 30 -1.6503845e+04 2.40e+04 4.67e+02 -1.0 1.60e+05 - 5.34e-02 4.11e-04f 1\n", + " 31 -1.6103557e+04 2.39e+04 1.51e+04 -1.0 5.35e+04 - 6.91e-02 1.53e-03h 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 32 -1.3109479e+04 2.37e+04 3.61e+04 -1.0 5.32e+04 - 1.16e-01 1.14e-02h 3\n", + " 33 -9.8778958e+03 2.34e+04 8.31e+04 -1.0 5.10e+04 - 2.78e-01 1.32e-02h 3\n", + " 34 -6.1943183e+03 2.30e+04 1.45e+05 -1.0 4.89e+04 - 5.07e-01 1.61e-02h 3\n", + " 35 -1.6595473e+03 2.25e+04 1.62e+05 -1.0 4.68e+04 - 3.19e-01 2.13e-02h 3\n", + " 36 5.4794139e+03 2.18e+04 1.85e+05 -1.0 4.46e+04 - 6.87e-01 3.60e-02h 3\n", + " 37 1.6365098e+04 2.05e+04 1.79e+05 -1.0 4.17e+04 - 3.54e-01 6.02e-02h 3\n", + " 38 2.7740530e+04 1.92e+04 1.68e+05 -1.0 3.80e+04 - 2.00e-01 7.01e-02h 3\n", + " 39 3.9763721e+04 1.78e+04 1.56e+05 -1.0 3.48e+04 - 2.45e-01 8.02e-02h 3\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 40 5.2469134e+04 1.64e+04 1.44e+05 -1.0 3.21e+04 - 3.86e-01 9.05e-02h 3\n", + " 41 6.5791945e+04 1.49e+04 1.34e+05 -1.0 2.96e+04 - 6.07e-01 1.01e-01h 3\n", + " 42 1.2096642e+05 1.17e+04 8.09e+04 -1.0 2.75e+04 - 8.69e-01 4.43e-01w 1\n", + " 43 1.3345225e+05 1.02e+04 9.69e+04 -1.0 2.10e+04 - 9.90e-01 1.33e-01w 1\n", + " 44 1.3364425e+05 1.02e+04 1.48e+05 -1.0 2.14e+04 - 1.00e+00 2.24e-03w 1\n", + " 45 7.9585562e+04 1.35e+04 1.27e+05 -1.0 2.14e+04 - 8.69e-01 1.11e-01h 2\n", + " 46 9.2643927e+04 1.22e+04 1.21e+05 -1.0 2.69e+04 - 9.90e-01 1.12e-01h 3\n", + " 47 1.1662879e+05 1.01e+04 1.01e+05 -1.0 2.65e+04 - 1.00e+00 2.21e-01h 2\n", + " 48 1.5635635e+05 6.66e+03 7.23e+04 -1.0 2.30e+04 - 1.00e+00 4.07e-01H 1\n", + " 49 1.5677484e+05 6.62e+03 9.35e+04 -1.0 1.77e+04 - 1.00e+00 6.00e-03h 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 50 1.5677903e+05 6.62e+03 9.06e+07 -1.0 1.77e+04 - 1.00e+00 6.03e-05h 1\n", + " 51r 1.5677903e+05 6.62e+03 1.00e+03 3.8 0.00e+00 - 0.00e+00 3.01e-07R 2\n", + " 52r 1.5677921e+05 2.60e+03 1.79e+03 3.8 6.62e+06 - 1.08e-02 9.90e-04f 1\n", + " 53 1.5639242e+05 2.60e+03 1.00e+02 -1.0 1.25e+05 - 5.02e-02 4.91e-04f 1\n", + " 54 1.5638540e+05 2.58e+03 7.78e+02 -1.0 1.53e+04 - 3.61e-01 7.65e-03h 1\n", + " 55 1.5639044e+05 2.58e+03 3.43e+06 -1.0 1.52e+04 - 7.08e-01 7.69e-05h 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 56r 1.5639044e+05 2.58e+03 1.00e+03 3.4 0.00e+00 - 0.00e+00 3.85e-07R 2\n", + " 57r 1.5639078e+05 7.01e+02 9.95e+02 3.4 2.58e+06 - 5.78e-03 9.91e-04f 1\n", + " 58 1.5614585e+05 7.00e+02 1.38e+02 -1.0 9.14e+04 - 6.54e-02 4.74e-04f 1\n", + " 59 1.5624013e+05 6.99e+02 4.69e+03 -1.0 1.57e+04 - 5.04e-01 2.61e-03h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 60 1.5624202e+05 6.99e+02 1.47e+08 -1.0 1.57e+04 - 8.22e-01 2.62e-05h 1\n", + " 61r 1.5624202e+05 6.99e+02 1.00e+03 2.8 0.00e+00 - 0.00e+00 1.31e-07R 2\n", + " 62r 1.5624284e+05 1.84e+02 9.98e+02 2.8 6.99e+05 - 2.70e-03 9.90e-04f 1\n", + " 63 1.5604488e+05 1.84e+02 1.65e+02 -1.0 7.47e+04 - 7.78e-02 4.95e-04f 1\n", + " 64 1.5606175e+05 1.84e+02 1.65e+05 -1.0 1.59e+04 - 5.42e-01 3.40e-04h 1\n", + " 65r 1.5606175e+05 1.84e+02 1.00e+03 2.3 0.00e+00 - 0.00e+00 4.26e-07R 4\n", + " 66r 1.5606221e+05 4.72e+01 4.65e+03 2.3 1.84e+05 - 3.00e-01 9.90e-04f 1\n", + " 67 1.5598771e+05 4.72e+01 4.39e+02 -1.0 6.50e+04 - 8.77e-02 2.22e-04f 1\n", + " 68r 1.5598771e+05 4.72e+01 9.99e+02 1.7 0.00e+00 - 0.00e+00 2.77e-07R 4\n", + " 69r 1.5598853e+05 1.22e+01 1.33e+03 1.7 4.72e+04 - 3.27e-01 9.90e-04f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 70 1.5594804e+05 1.22e+01 7.89e+02 -1.0 6.09e+04 - 9.21e-02 1.30e-04f 1\n", + " 71r 1.5594804e+05 1.22e+01 9.99e+02 1.1 0.00e+00 - 0.00e+00 3.24e-07R 3\n", + " 72r 1.5594931e+05 5.34e+01 9.49e+02 1.1 1.22e+04 - 1.28e-01 9.90e-04f 1\n", + " 73r 1.5602328e+05 8.38e+03 8.47e+02 1.1 1.82e+02 - 3.97e-01 1.18e-01f 1\n", + " 74r 1.5611223e+05 5.32e+03 5.09e+02 1.1 1.27e+02 - 4.87e-01 3.88e-01f 1\n", + " 75r 1.5611538e+05 4.46e+03 9.27e+02 1.1 4.35e+01 - 3.30e-01 2.08e-01f 1\n", + " 76r 1.5618738e+05 4.27e+03 3.31e+02 1.1 6.22e+01 - 8.72e-01 5.98e-01f 1\n", + " 77r 1.5626949e+05 2.10e+04 5.81e+03 1.1 2.66e+02 - 6.87e-01 1.00e+00f 1\n", + " 78r 1.5626950e+05 9.45e+02 1.67e+03 1.1 2.44e+00 0.0 9.93e-01 9.56e-01h 1\n", + " 79r 1.5633952e+05 1.55e+03 6.08e+02 1.1 7.00e+01 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 80r 1.5642050e+05 1.38e+02 4.09e+01 1.1 1.25e+01 - 1.00e+00 1.00e+00h 1\n", + " 81r 1.5640166e+05 1.18e+00 1.13e+00 1.1 2.52e+00 - 1.00e+00 1.00e+00h 1\n", + " 82 1.4211718e+05 4.18e+02 7.70e+02 -1.0 7.62e+05 - 5.86e-03 2.54e-03f 1\n", + " 83r 1.4211718e+05 4.18e+02 9.99e+02 2.6 0.00e+00 - 0.00e+00 4.73e-07R 15\n", + " 84r 1.4211760e+05 9.63e+01 7.10e+03 2.6 4.18e+05 - 2.71e-02 9.90e-04f 1\n", + " 85 1.4189541e+05 9.64e+01 3.92e+02 -1.0 3.81e+05 - 1.62e-02 7.48e-05f 1\n", + " 86 1.4037132e+05 2.61e+03 1.06e+03 -1.0 1.60e+04 - 3.64e-02 1.33e-02f 1\n", + " 87 1.4037496e+05 2.61e+03 1.03e+06 -1.0 2.99e+04 - 9.60e-02 1.34e-04h 1\n", + " 88r 1.4037496e+05 2.61e+03 1.00e+03 3.4 0.00e+00 - 0.00e+00 3.35e-07R 3\n", + " 89r 1.4037548e+05 1.23e+03 1.25e+04 3.4 2.61e+06 - 2.16e-02 9.90e-04f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 90 1.3159180e+05 1.24e+03 1.40e+01 -1.0 1.15e+06 - 1.26e-02 8.35e-04f 1\n", + " 91 1.3048033e+05 1.24e+03 5.90e+01 -1.0 5.18e+04 - 2.81e-02 2.55e-03f 1\n", + " 92 1.3047951e+05 1.24e+03 2.51e+05 -1.0 3.24e+04 - 1.03e-01 2.56e-05f 1\n", + " 93r 1.3047951e+05 1.24e+03 1.00e+03 3.1 0.00e+00 - 0.00e+00 1.28e-07R 2\n", + " 94r 1.3047961e+05 3.22e+02 7.99e+03 3.1 1.24e+06 - 1.28e-01 9.91e-04f 1\n", + " 95 1.2799595e+05 3.22e+02 3.48e+01 -1.0 2.84e+05 - 2.91e-02 8.14e-04f 1\n", + " 96 1.2798856e+05 3.21e+02 2.37e+03 -1.0 3.80e+04 - 8.68e-02 7.83e-04f 1\n", + " 97r 1.2798856e+05 3.21e+02 1.00e+03 2.5 0.00e+00 - 0.00e+00 4.90e-07R 5\n", + " 98r 1.2798821e+05 8.75e+01 6.36e+03 2.5 3.21e+05 - 3.92e-01 9.90e-04f 1\n", + " 99 1.2802319e+05 8.74e+01 1.07e+04 -1.0 4.00e+04 - 1.87e-01 4.16e-04h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 100r 1.2802319e+05 8.74e+01 1.00e+03 1.9 0.00e+00 - 0.00e+00 2.60e-07R 5\n", + " 101r 1.2802286e+05 2.25e+01 1.59e+03 1.9 8.74e+04 - 3.57e-01 9.90e-04f 1\n", + " 102 1.2803524e+05 2.24e+01 3.21e+05 -1.0 4.04e+04 - 3.46e-01 1.15e-04h 1\n", + " 103r 1.2803524e+05 2.24e+01 1.00e+03 1.4 0.00e+00 - 0.00e+00 2.87e-07R 3\n", + " 104r 1.2803522e+05 5.73e+00 9.93e+02 1.4 2.24e+04 - 3.75e-01 9.90e-04f 1\n", + " 105 1.2801361e+05 5.73e+00 1.41e+03 -1.0 5.87e+04 - 3.71e-02 2.95e-05f 1\n", + " 106r 1.2801361e+05 5.73e+00 1.00e+03 0.8 0.00e+00 - 0.00e+00 1.48e-07R 2\n", + " 107r 1.2801478e+05 2.68e+00 9.89e+02 0.8 5.73e+03 - 8.71e-02 9.90e-04f 1\n", + " 108 1.2800949e+05 2.68e+00 5.60e+03 -1.0 5.63e+04 - 3.78e-02 7.54e-06f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 109r 1.2800949e+05 2.68e+00 1.00e+03 0.4 0.00e+00 - 0.00e+00 3.77e-08R 2\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 110r 1.2801166e+05 3.81e+00 9.93e+02 0.4 2.68e+03 - 3.82e-02 9.90e-04f 1\n", + " 111r 1.2802445e+05 6.14e+02 9.64e+02 0.4 3.09e+02 - 2.66e-02 2.94e-02f 1\n", + " 112r 1.2806075e+05 1.08e+03 8.98e+02 0.4 1.58e+02 - 2.79e-01 5.62e-02f 1\n", + " 113r 1.2831404e+05 1.07e+03 6.34e+02 0.4 1.43e+02 - 7.40e-01 3.03e-01f 1\n", + " 114r 1.2886030e+05 3.98e+03 2.01e+02 0.4 5.86e+01 - 9.64e-01 8.55e-01f 1\n", + " 115r 1.2885846e+05 5.59e+03 3.81e+03 0.4 1.76e+01 -2.0 7.49e-01 9.89e-01F 1\n", + " 116r 1.2885837e+05 5.02e+03 1.59e+03 0.4 3.19e+01 -1.6 1.26e-01 1.01e-01h 1\n", + " 117r 1.2875688e+05 7.27e+03 8.69e+03 0.4 1.70e+02 - 9.01e-01 6.08e-01H 1\n", + " 118r 1.2861391e+05 1.91e+03 2.32e+03 0.4 6.76e+01 - 3.09e-01 4.96e-01h 1\n", + " 119r 1.2861391e+05 1.18e+03 1.30e+03 0.4 7.62e-01 0.7 2.63e-01 3.79e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 120r 1.2861391e+05 1.50e+01 1.60e+03 0.4 1.12e+00 0.2 1.00e+00 1.00e+00f 1\n", + " 121r 1.2855214e+05 1.41e+03 6.30e+02 0.4 2.14e+02 - 7.06e-01 6.45e-01F 1\n", + " 122r 1.2854036e+05 1.62e+02 2.13e+01 0.4 1.05e+01 - 1.00e+00 1.00e+00f 1\n", + " 123r 1.2854284e+05 6.41e+01 1.88e+00 0.4 5.18e+00 - 1.00e+00 1.00e+00h 1\n", + " 124r 1.2854112e+05 1.24e+00 5.76e-02 0.4 5.06e-01 - 1.00e+00 1.00e+00h 1\n", + " 125 1.2853731e+05 8.25e+00 8.46e+01 -1.0 3.52e+04 - 2.13e-03 1.10e-04f 6\n", + " 126 1.2853574e+05 1.02e+01 1.68e+02 -1.0 3.46e+04 - 3.78e-03 5.51e-05f 7\n", + " 127 1.2853471e+05 1.22e+01 3.97e+02 -1.0 3.51e+04 - 5.15e-03 5.52e-05f 7\n", + " 128 1.2853431e+05 1.41e+01 9.42e+02 -1.0 3.57e+04 - 5.14e-03 5.54e-05f 7\n", + " 129r 1.2853431e+05 1.41e+01 9.99e+02 1.2 0.00e+00 - 0.00e+00 4.36e-07R 14\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 130r 1.2853521e+05 3.27e+00 3.14e+03 1.2 1.41e+04 - 6.27e-02 9.90e-04f 1\n", + " 131 1.2034467e+05 2.66e+02 3.47e+02 -1.0 1.47e+06 - 2.72e-03 6.73e-04f 1\n", + " 132 1.2022266e+05 4.31e+03 1.11e+03 -1.0 2.32e+04 - 6.56e-03 2.99e-03f 1\n", + " 133r 1.2022266e+05 4.31e+03 9.99e+02 3.6 0.00e+00 - 0.00e+00 4.67e-07R 7\n", + " 134r 1.2022335e+05 8.51e+03 7.19e+03 3.6 4.31e+06 - 1.68e-02 9.90e-04f 1\n", + " 135r 1.2022365e+05 8.36e+03 7.04e+03 2.2 5.51e+04 - 8.33e-01 1.76e-02f 1\n", + " 136r 1.2028738e+05 2.34e+05 4.43e+03 2.2 4.33e+02 - 5.63e-01 8.32e-01f 1\n", + " 137r 1.2028745e+05 8.35e+04 1.36e+03 2.2 1.19e+01 0.0 5.50e-01 7.32e-01f 1\n", + " 138r 1.2031198e+05 5.29e+04 7.87e+02 2.2 1.46e+02 - 6.30e-01 6.77e-01f 1\n", + " 139r 1.2030652e+05 2.46e+04 1.31e+03 2.2 5.31e+01 - 9.14e-01 8.25e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 140r 1.2030840e+05 2.40e+04 1.29e+03 2.2 3.56e+01 - 1.86e-02 2.50e-02h 1\n", + " 141r 1.2030840e+05 2.36e+04 1.25e+03 2.2 9.18e+00 2.2 3.84e-02 1.35e-02h 1\n", + " 142r 1.2033359e+05 1.95e+04 8.08e+03 2.2 4.55e+01 - 5.22e-01 2.17e-01f 1\n", + " 143r 1.2038554e+05 3.79e+04 1.15e+03 2.2 5.04e+01 - 1.00e+00 1.00e+00f 1\n", + " 144r 1.2036898e+05 1.43e+04 8.09e+02 2.2 2.28e+01 - 1.00e+00 1.00e+00f 1\n", + " 145r 1.2047190e+05 5.00e+03 3.01e+02 2.2 5.23e+01 - 1.00e+00 7.53e-01h 1\n", + " 146r 1.2043452e+05 2.24e+03 2.42e+03 2.2 1.02e+01 - 1.00e+00 5.61e-01f 1\n", + " 147r 1.2041013e+05 4.32e+03 1.02e+03 2.2 1.51e+01 - 1.00e+00 5.72e-01f 1\n", + " 148r 1.2041937e+05 4.84e+02 1.91e+02 2.2 3.50e+00 - 1.00e+00 1.00e+00f 1\n", + " 149 1.1303874e+05 5.57e+03 4.76e+02 -1.0 2.96e+05 - 3.61e-03 2.13e-03f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 150 1.1050904e+05 5.53e+03 3.99e+02 -1.0 1.56e+05 - 8.49e-03 1.87e-03f 1\n", + " 151 1.1027960e+05 5.52e+03 4.08e+02 -1.0 7.06e+04 - 1.08e-02 3.88e-04f 1\n", + " 152 1.1027853e+05 5.52e+03 3.78e+05 -1.0 3.54e+04 - 1.88e-02 4.05e-06f 1\n", + " 153r 1.1027853e+05 5.52e+03 1.00e+03 3.7 0.00e+00 - 0.00e+00 2.03e-08R 2\n", + " 154r 1.1027886e+05 6.60e+02 2.29e+03 3.7 5.51e+06 - 3.42e-03 9.93e-04f 1\n", + " 155 1.0759473e+05 6.61e+02 2.40e+01 -1.0 1.36e+06 - 5.20e-03 2.07e-04f 1\n", + " 156 1.0758344e+05 6.61e+02 1.68e+05 -1.0 5.36e+05 - 1.38e-02 2.11e-06f 1\n", + " 157r 1.0758344e+05 6.61e+02 9.99e+02 2.8 0.00e+00 - 0.00e+00 1.06e-08R 2\n", + " 158r 1.0758424e+05 1.76e+02 9.97e+02 2.8 6.61e+05 - 1.95e-03 9.90e-04f 1\n", + " 159 1.0727225e+05 1.76e+02 2.26e+02 -1.0 1.28e+06 - 5.75e-03 2.52e-05f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 160 1.0727102e+05 1.76e+02 1.38e+07 -1.0 4.83e+05 - 1.54e-02 2.52e-07f 1\n", + " 161r 1.0727102e+05 1.76e+02 1.00e+03 2.2 0.00e+00 - 0.00e+00 2.10e-09R 2\n", + " 162r 1.0727100e+05 4.49e+01 3.89e+03 2.2 1.76e+05 - 3.33e-01 9.90e-04f 1\n", + " 163 1.0718953e+05 4.49e+01 8.71e+02 -1.0 1.28e+06 - 5.81e-03 6.62e-06f 1\n", + " 164 1.0718937e+05 4.49e+01 2.04e+08 -1.0 4.76e+05 - 1.56e-02 3.31e-08f 2\n", + " 165 1.0719074e+05 4.49e+01 2.41e+12 -1.0 1.39e+07 - 3.27e-04 2.74e-08H 1\n", + " 166r 1.0719074e+05 4.49e+01 1.00e+03 1.7 0.00e+00 - 0.00e+00 1.84e-11R 2\n", + " 167r 1.0719095e+05 1.12e+01 9.90e+02 1.7 4.49e+04 - 1.70e-01 9.90e-04f 1\n", + " 168 1.0717059e+05 1.12e+01 3.49e+03 -1.0 1.27e+06 - 5.83e-03 1.66e-06f 1\n", + " 169r 1.0717059e+05 1.12e+01 9.99e+02 1.0 0.00e+00 - 0.00e+00 8.30e-09R 2\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 170r 1.0717179e+05 3.98e+00 9.97e+02 1.0 1.12e+04 - 7.26e-02 9.90e-04f 1\n", + " 171 1.0716685e+05 3.98e+00 1.42e+04 -1.0 1.24e+06 - 5.88e-03 4.11e-07f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 172r 1.0716685e+05 3.98e+00 9.99e+02 0.6 0.00e+00 - 0.00e+00 2.06e-09R 2\n", + " 173r 1.0716902e+05 1.22e+01 9.95e+02 0.6 3.98e+03 - 2.60e-02 9.90e-04f 1\n", + " 174r 1.0721151e+05 3.96e+03 9.71e+02 0.6 7.43e+02 - 5.48e-02 2.49e-02f 1\n", + " 175r 1.0733554e+05 8.77e+03 8.92e+02 0.6 7.42e+02 - 2.07e-01 7.93e-02f 1\n", + " 176r 1.0744861e+05 1.81e+04 3.21e+03 0.6 6.39e+02 - 2.76e-01 9.12e-02f 1\n", + " 177r 1.0760156e+05 1.26e+04 2.49e+03 0.6 4.84e+02 - 1.35e-01 1.57e-01f 1\n", + " 178r 1.0759534e+05 1.76e+04 3.00e+03 0.6 8.50e+01 - 2.93e-01 1.80e-01f 1\n", + " 179r 1.0769358e+05 1.54e+04 3.69e+03 0.6 5.91e+01 - 3.85e-01 2.13e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 180r 1.0817736e+05 6.68e+03 3.86e+03 0.6 1.21e+02 - 9.01e-01 5.48e-01f 1\n", + " 181r 1.0810596e+05 6.25e+03 2.22e+03 0.6 6.69e+01 - 3.03e-01 3.61e-01f 1\n", + " 182r 1.0804719e+05 1.30e+03 4.59e+02 0.6 3.46e+01 - 9.90e-01 1.00e+00f 1\n", + " 183r 1.0811628e+05 1.96e+02 1.22e+01 0.6 2.24e+01 - 1.00e+00 1.00e+00f 1\n", + " 184r 1.0810982e+05 6.43e+00 3.18e+00 0.6 9.06e-01 - 1.00e+00 1.00e+00h 1\n", + " 185r 1.0822116e+05 9.78e+02 1.36e+02 -0.8 6.25e+01 - 7.37e-01 6.38e-01f 1\n", + " 186r 1.1108726e+05 1.47e+03 9.49e+01 -0.8 1.17e+03 - 7.44e-01 5.74e-01f 1\n", + " 187r 1.1267097e+05 5.05e+03 8.55e+01 -0.8 5.95e+02 - 1.00e+00 7.56e-01f 1\n", + " 188r 1.1279724e+05 1.61e+03 1.89e+01 -0.8 1.03e+02 - 6.41e-01 6.99e-01h 1\n", + " 189r 1.1300124e+05 7.91e+01 5.00e-01 -0.8 6.37e+01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 190r 1.1300781e+05 1.88e+00 3.19e-02 -0.8 9.42e-01 - 1.00e+00 1.00e+00h 1\n", + " 191r 1.1300781e+05 1.88e+00 9.99e+02 0.3 0.00e+00 - 0.00e+00 1.25e-09R 2\n", + " 192r 1.1300966e+05 4.83e-01 2.16e+04 0.3 1.88e+03 - 8.88e-02 9.90e-04f 1\n", + " 193r 1.1300966e+05 4.83e-01 9.99e+02 -0.3 0.00e+00 - 0.00e+00 1.49e-09R 2\n", + " 194r 1.1301306e+05 1.93e-01 1.24e+04 -0.3 8.04e+02 - 2.20e-01 9.90e-04f 1\n", + " 195r 1.1301306e+05 1.93e-01 9.99e+02 -0.7 0.00e+00 - 0.00e+00 1.56e-09R 2\n", + " 196r 1.1302132e+05 1.93e-01 2.17e+04 -0.7 1.31e+03 - 9.64e-01 1.54e-03f 1\n", + " 197r 1.1823161e+05 6.17e+02 4.80e+02 -0.7 1.34e+03 - 9.89e-01 9.61e-01f 1\n", + " 198r 1.1798536e+05 5.28e+02 6.49e+01 -0.7 5.91e+01 - 7.43e-01 1.00e+00h 1\n", + " 199r 1.1805718e+05 2.99e+02 3.87e+00 -0.7 1.29e+01 - 9.93e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 200r 1.1805876e+05 8.10e+01 1.75e+00 -0.7 3.71e+00 - 1.00e+00 1.00e+00h 1\n", + " 201r 1.1806057e+05 5.70e-01 1.05e-03 -0.7 4.13e-01 - 1.00e+00 1.00e+00h 1\n", + " 202r 1.1811792e+05 3.68e+02 9.69e+00 -1.4 2.10e+01 - 9.31e-01 9.67e-01f 1\n", + " 203r 1.2050787e+05 7.67e+02 6.64e+01 -1.4 1.57e+03 - 6.63e-01 5.35e-01h 1\n", + " 204r 1.2249012e+05 4.59e+02 1.35e+02 -1.4 7.27e+02 - 6.94e-01 1.00e+00h 1\n", + " 205r 1.2248902e+05 6.11e+02 4.56e+01 -1.4 3.65e+00 - 1.00e+00 1.00e+00h 1\n", + " 206r 1.2249445e+05 1.16e+02 6.38e+00 -1.4 7.80e-01 - 1.00e+00 1.00e+00h 1\n", + " 207r 1.2249392e+05 1.06e+00 1.19e-01 -1.4 7.63e-02 - 1.00e+00 1.00e+00h 1\n", + " 208r 1.2249396e+05 1.76e-01 3.39e-05 -1.4 6.38e-03 - 1.00e+00 1.00e+00h 1\n", + " 209r 1.2253738e+05 1.27e+02 1.74e+01 -3.2 1.09e+01 - 9.28e-01 8.33e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 210r 1.2342956e+05 2.40e+03 2.42e+02 -3.2 1.70e+04 - 4.06e-01 1.26e-01f 1\n", + " 211r 1.2343158e+05 2.40e+03 7.66e+02 -3.2 8.82e+03 - 2.08e-01 1.77e-04h 1\n", + " 212r 1.2680154e+05 2.07e+03 8.71e+02 -3.2 2.55e+03 - 3.91e-01 1.86e-01h 1\n", + " 213r 1.2680301e+05 2.06e+03 1.05e+03 -3.2 9.06e+01 - 7.96e-01 5.94e-03h 1\n", + " 214r 1.2694462e+05 1.25e+03 8.56e+02 -3.2 7.71e+01 - 1.00e+00 3.94e-01h 1\n", + " 215r 1.2716494e+05 2.37e+03 2.47e+02 -3.2 4.31e+01 - 1.00e+00 1.00e+00h 1\n", + " 216r 1.2716480e+05 3.75e+02 2.05e+02 -3.2 1.32e+00 - 8.45e-01 9.35e-01h 1\n", + " 217r 1.2716432e+05 2.49e+01 7.82e+01 -3.2 2.34e-01 - 1.00e+00 9.40e-01h 1\n", + " 218r 1.2716443e+05 1.57e+00 2.02e+00 -3.2 1.03e-01 - 1.00e+00 1.00e+00h 1\n", + " 219r 1.2716444e+05 1.72e-01 1.84e-02 -3.2 3.20e-02 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 220 1.2716441e+05 1.72e-01 5.84e+02 -1.0 3.35e+04 - 1.89e-04 1.11e-06f 3\n", + " 221 1.2716433e+05 1.72e-01 6.98e+03 -1.0 3.33e+04 - 5.76e-04 3.00e-06f 2\n", + " 222 1.2716001e+05 6.59e-01 6.09e+03 -1.0 3.26e+04 - 1.20e-04 1.53e-04f 1\n", + " 223 1.2715671e+05 9.98e-01 2.65e+04 -1.0 3.24e+04 - 8.81e-04 1.13e-04f 2\n", + " 224 1.2715642e+05 1.00e+00 3.99e+04 -1.0 3.21e+04 - 5.12e-04 1.02e-05f 8\n", + " 225 1.2715609e+05 1.00e+00 2.11e+05 -1.0 3.20e+04 - 6.44e-03 1.21e-05f 8\n", + " 226 1.2715594e+05 1.01e+00 2.22e+05 -1.0 3.12e+04 - 4.13e-04 7.29e-06f 9\n", + " 227 1.2715578e+05 1.01e+00 6.06e+05 -1.0 3.12e+04 - 1.45e-02 7.28e-06f 9\n", + " 228 1.2712455e+05 5.74e+01 5.61e+05 -1.0 2.98e+04 - 4.34e-04 2.11e-03f 1\n", + " 229 1.2712496e+05 5.76e+01 5.61e+05 -1.0 2.47e+04 - 1.73e-04 1.73e-04s 10\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 230 1.2713698e+05 1.14e+02 5.59e+05 -1.0 2.41e+04 - 2.70e-03 2.70e-03s 10\n", + " 231r 1.2713698e+05 1.14e+02 1.00e+03 2.1 0.00e+00 - 0.00e+00 0.00e+00R 1\n", + " 232r 1.2716197e+05 1.69e+03 3.15e+04 2.1 1.14e+05 - 1.07e-05 2.61e-04f 1\n", + " 233r 1.2714570e+05 2.14e+03 2.94e+04 2.1 8.31e+04 - 5.38e-04 1.00e-03f 1\n", + " 234r 1.2714342e+05 2.61e+03 2.90e+04 2.1 1.04e+04 - 2.06e-03 1.77e-03f 1\n", + " 235r 1.2713596e+05 3.50e+03 2.84e+04 2.1 1.57e+03 - 3.35e-03 4.25e-03f 1\n", + " 236r 1.2708154e+05 5.65e+03 2.84e+04 2.1 7.55e+02 - 2.00e-03 1.09e-02f 1\n", + " 237r 1.2708154e+05 5.08e+03 2.48e+04 2.1 8.00e+00 2.0 2.43e-02 1.02e-01f 1\n", + " 238r 1.2708154e+05 4.85e+03 2.33e+04 2.1 8.06e+00 1.5 3.31e-01 4.61e-02f 1\n", + " 239r 1.2708156e+05 1.14e+04 2.24e+04 2.1 2.91e+02 1.0 8.89e-03 1.92e-02f 2\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 240r 1.2708156e+05 3.64e+03 1.67e+03 2.1 3.56e-01 3.3 9.90e-01 9.24e-01f 1\n", + " 241r 1.2726934e+05 1.67e+04 1.27e+04 2.1 2.58e+02 - 4.63e-01 1.00e+00f 1\n", + " 242r 1.2736337e+05 1.24e+03 6.79e+01 2.1 2.54e+01 - 1.00e+00 1.00e+00f 1\n", + " 243r 1.2744147e+05 1.56e+03 1.20e+02 2.1 8.73e+01 - 1.00e+00 1.00e+00f 1\n", + " 244r 1.2739248e+05 1.69e+04 1.76e+02 2.1 4.12e+01 - 1.00e+00 1.00e+00f 1\n", + " 245r 1.2738697e+05 6.55e+02 5.20e+00 2.1 6.39e+00 - 1.00e+00 1.00e+00h 1\n", + " 246r 1.2749175e+05 1.38e+04 1.09e+03 1.4 1.60e+02 - 4.91e-01 7.12e-01f 1\n", + " 247r 1.2761275e+05 2.71e+03 4.74e+02 1.4 6.53e+01 - 6.43e-01 1.00e+00f 1\n", + " 248r 1.2750105e+05 1.80e+03 4.59e+01 1.4 3.96e+01 - 1.00e+00 1.00e+00f 1\n", + " 249r 1.2754311e+05 6.91e+01 1.63e+01 1.4 1.22e+01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 250r 1.2731384e+05 3.27e+03 7.52e+01 0.7 9.90e+01 - 9.32e-01 9.07e-01f 1\n", + " 251r 1.2733916e+05 3.31e+03 3.81e+02 0.7 2.94e+01 - 9.88e-01 1.00e+00f 1\n", + " 252r 1.2733916e+05 7.28e+00 2.53e+01 0.7 3.71e-02 2.8 1.00e+00 1.00e+00h 1\n", + " 253 1.2683674e+05 7.41e+03 1.23e+04 -1.0 3.89e+05 - 1.95e-04 3.22e-04f 1\n", + " 254 1.2676691e+05 7.46e+03 1.24e+04 -1.0 3.46e+05 - 8.15e-04 8.67e-05f 1\n", + " 255 1.2676634e+05 7.46e+03 1.25e+04 -1.0 3.35e+05 - 4.00e-06 1.86e-05f 1\n", + " 256r 1.2676634e+05 7.46e+03 9.99e+02 3.9 0.00e+00 - 0.00e+00 2.79e-07R 11\n", + " 257r 1.2676664e+05 6.95e+03 1.73e+03 3.9 7.46e+06 - 9.44e-06 6.75e-05f 1\n", + " 258r 1.2676749e+05 1.45e+04 4.19e+03 3.9 6.89e+06 - 5.87e-03 2.42e-04f 1\n", + " 259r 1.2677021e+05 2.06e+04 1.68e+05 3.9 7.68e+05 - 2.42e-01 6.81e-03f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 260r 1.2676657e+05 1.54e+04 1.99e+04 3.2 2.06e+03 - 7.98e-01 2.46e-01f 1\n", + " 261r 1.2679614e+05 1.25e+05 6.11e+04 3.2 4.23e+02 - 6.64e-01 9.18e-01f 1\n", + " 262r 1.2679614e+05 1.06e+05 5.24e+04 3.2 2.15e+01 2.0 2.47e-01 1.50e-01h 1\n", + " 263r 1.2679699e+05 9.96e+04 4.99e+04 3.2 3.45e+02 - 1.19e-01 5.68e-02f 1\n", + " 264r 1.2667363e+05 3.90e+04 1.72e+04 3.2 9.75e+01 - 1.00e+00 9.82e-01f 1\n", + " 265r 1.2671998e+05 8.46e+04 5.46e+03 3.2 4.82e+01 - 9.57e-01 1.00e+00f 1\n", + " 266r 1.2672645e+05 3.56e+04 8.81e+03 3.2 3.41e+01 - 7.54e-01 5.00e-01f 2\n", + " 267r 1.2673515e+05 2.88e+04 2.96e+03 3.2 3.52e+01 - 8.41e-01 5.00e-01h 2\n", + " 268r 1.2674045e+05 2.96e+04 5.20e+02 3.2 1.42e+01 - 1.00e+00 1.00e+00h 1\n", + " 269r 1.2670264e+05 4.00e+04 1.89e+03 3.2 4.20e+01 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 270r 1.2671520e+05 2.66e+04 2.95e+03 3.2 3.23e+01 - 1.00e+00 5.00e-01h 2\n", + " 271r 1.2674449e+05 1.92e+04 6.30e+02 3.2 3.26e+01 - 1.00e+00 1.00e+00h 1\n", + " 272r 1.2667937e+05 1.21e+04 1.31e+03 3.2 4.68e+01 - 8.60e-01 8.81e-01H 1\n", + " 273r 1.2675843e+05 1.14e+05 1.38e+03 2.5 2.14e+02 - 9.15e-01 9.58e-01f 1\n", + " 274r 1.2689727e+05 2.02e+04 6.57e+02 2.5 1.53e+02 - 8.86e-01 9.29e-01f 1\n", + " 275r 1.2682834e+05 4.79e+03 1.01e+03 2.5 8.87e+01 - 1.29e-01 1.00e+00f 1\n", + " 276r 1.2683302e+05 7.29e+03 2.75e+01 2.5 1.48e+01 - 1.00e+00 1.00e+00f 1\n", + " 277r 1.2683771e+05 1.69e+02 2.08e+00 2.5 2.17e+00 - 1.00e+00 1.00e+00h 1\n", + " 278 9.8178178e+04 4.74e+03 3.17e+02 -1.0 1.14e+06 - 4.18e-03 3.73e-03f 1\n", + " 279 9.7892691e+04 4.74e+03 4.16e+02 -1.0 3.14e+05 - 1.05e-02 8.44e-05f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 280 9.7891957e+04 4.74e+03 6.56e+06 -1.0 9.57e+04 - 1.40e-02 8.51e-07f 1\n", + " 281 9.7890561e+04 4.74e+03 1.74e+11 -1.0 2.12e+07 - 2.28e-04 8.51e-09f 1\n", + " 282 8.8769650e+04 4.74e+03 7.10e+11 -1.0 7.63e+07 - 7.92e-05 1.93e-05f 1\n", + " 283r 8.8769650e+04 4.74e+03 1.00e+03 3.7 0.00e+00 - 0.00e+00 7.21e-12R 2\n", + " 284r 8.8769664e+04 3.34e+03 2.82e+04 3.7 4.74e+06 - 5.33e-02 2.94e-04f 1\n", + " 285 8.8693654e+04 3.34e+03 3.82e+02 -1.0 1.57e+05 - 1.43e-04 4.15e-05f 1\n", + " 286 8.8692951e+04 3.34e+03 2.28e+03 -1.0 1.43e+05 - 2.18e-04 4.17e-07f 1\n", + " 287r 8.8692951e+04 3.34e+03 9.99e+02 3.5 0.00e+00 - 0.00e+00 2.08e-09R 2\n", + " 288r 8.8692949e+04 3.30e+03 4.79e+03 3.5 3.34e+06 - 1.41e-03 1.30e-05f 1\n", + " 289r 8.8693153e+04 5.46e+02 4.17e+04 3.5 1.37e+06 - 1.36e-01 2.38e-03f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 290 8.7457681e+04 5.52e+02 9.15e+02 -1.0 3.59e+05 - 1.38e-02 3.41e-04f 1\n", + " 291 8.7456415e+04 5.52e+02 4.84e+06 -1.0 5.31e+04 - 1.82e-02 3.49e-06f 1\n", + " 292r 8.7456415e+04 5.52e+02 1.00e+03 2.7 0.00e+00 - 0.00e+00 1.76e-08R 2\n", + " 293r 8.7456389e+04 1.39e+02 2.42e+04 2.7 5.52e+05 - 4.97e-01 9.90e-04f 1\n", + " 294 8.7370462e+04 1.39e+02 5.88e+02 -1.0 3.62e+05 - 1.40e-02 2.36e-05f 1\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " 295r 8.7370462e+04 1.39e+02 9.99e+02 2.1 0.00e+00 - 0.00e+00 1.18e-07R 2\n", + " 296r 8.7370048e+04 3.52e+01 3.53e+03 2.1 1.39e+05 - 2.88e-01 9.90e-04f 1\n", + " 297 8.7365867e+04 3.52e+01 8.57e+03 -1.0 5.17e+04 - 1.49e-02 1.02e-05f 1\n", + " 298r 8.7365867e+04 3.52e+01 1.00e+03 1.5 0.00e+00 - 0.00e+00 5.08e-08R 2\n", + " 299r 8.7366392e+04 9.28e+00 9.94e+02 1.5 3.52e+04 - 2.03e-01 9.90e-04f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 300 8.7366287e+04 9.28e+00 8.33e+05 -1.0 7.00e+04 - 1.52e-02 7.75e-07f 2\n", + " 301r 8.7366287e+04 9.28e+00 1.00e+03 1.0 0.00e+00 - 0.00e+00 3.92e-07R 2\n", + " 302r 8.7367439e+04 1.24e+01 1.01e+03 1.0 9.28e+03 - 3.08e-02 9.90e-04f 1\n", + " 303r 8.7397075e+04 3.59e+03 9.77e+02 1.0 3.75e+02 - 1.00e-01 2.88e-02f 1\n", + " 304r 8.7438378e+04 3.48e+03 9.08e+02 1.0 3.31e+02 - 8.91e-02 4.71e-02f 1\n", + " 305r 8.7508053e+04 5.97e+03 1.50e+03 1.0 2.88e+02 - 4.19e-01 8.34e-02f 1\n", + " 306r 8.7712845e+04 2.48e+04 3.57e+03 1.0 2.81e+02 - 8.23e-01 3.25e-01f 1\n", + " 307r 8.7793008e+04 1.34e+04 2.30e+03 1.0 5.17e+01 - 4.78e-01 4.32e-01f 1\n", + " 308r 8.7846425e+04 7.72e+03 1.02e+03 1.0 2.62e+01 - 7.14e-01 6.69e-01f 1\n", + " 309r 8.7909231e+04 2.83e+03 4.55e+03 1.0 2.21e+01 - 9.91e-01 6.64e-01f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 310r 8.7935450e+04 1.38e+03 2.75e+03 1.0 1.16e+01 - 6.88e-01 5.11e-01f 1\n", + " 311r 8.7934743e+04 7.89e+01 4.04e+02 1.0 5.65e+00 - 1.00e+00 1.00e+00f 1\n", + " 312r 8.7774627e+04 2.97e+03 1.68e+02 0.3 4.16e+01 - 9.23e-01 9.88e-01f 1\n", + " 313r 8.8807837e+04 4.00e+03 1.24e+01 0.3 1.93e+02 - 1.00e+00 1.00e+00h 1\n", + " 314r 8.8874130e+04 2.92e+02 1.89e+00 0.3 9.71e+00 - 1.00e+00 1.00e+00h 1\n", + " 315r 8.8879501e+04 1.07e+00 1.78e-02 0.3 1.06e+00 - 1.00e+00 1.00e+00h 1\n", + " 316r 8.8879501e+04 1.07e+00 9.99e+02 0.0 0.00e+00 - 0.00e+00 2.69e-07R 2\n", + " 317r 8.8881473e+04 2.72e-01 1.76e+04 0.0 1.07e+03 - 9.21e-01 9.90e-04f 1\n", + " 318r 8.8881473e+04 2.72e-01 9.99e+02 -0.6 0.00e+00 - 0.00e+00 2.66e-07R 2\n", + " 319r 8.8884807e+04 2.82e-01 1.14e+03 -0.6 7.03e+02 - 2.34e-01 9.90e-04f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 320r 8.9636313e+04 9.61e+02 5.59e+03 -0.6 8.27e+02 - 8.63e-01 1.73e-01f 1\n", + " 321r 9.0993769e+04 1.08e+03 5.48e+03 -0.6 7.71e+02 - 5.54e-01 3.35e-01f 1\n", + " 322r 9.2474307e+04 2.15e+03 5.68e+03 -0.6 4.81e+02 - 8.60e-01 5.30e-01f 1\n", + " 323r 9.3478773e+04 1.06e+03 1.62e+03 -0.6 1.77e+02 - 9.90e-01 8.80e-01h 1\n", + " 324r 9.3554925e+04 1.01e+02 2.92e+01 -0.6 1.84e+01 - 9.96e-01 1.00e+00h 1\n", + " 325r 9.3556224e+04 1.65e-01 1.08e-02 -0.6 2.08e-01 - 1.00e+00 1.00e+00h 1\n", + " 326r 9.3556224e+04 1.65e-01 9.99e+02 -0.8 0.00e+00 - 0.00e+00 2.98e-10R 2\n", + " 327r 9.3571208e+04 1.65e-01 1.76e+04 -0.8 9.65e+02 - 8.70e-01 2.51e-03f 1\n", + " 328r 9.8897161e+04 1.50e+03 3.13e+03 -0.8 1.01e+03 - 9.59e-01 8.71e-01f 1\n", + " 329r 9.8336345e+04 5.99e+01 1.09e+02 -0.8 7.97e+01 - 9.90e-01 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 330r 9.8338262e+04 4.49e-01 4.27e-01 -0.8 3.37e+00 - 9.95e-01 1.00e+00h 1\n", + " 331r 9.8363923e+04 2.98e+02 1.32e+02 -1.5 9.78e+00 - 1.00e+00 9.63e-01f 1\n", + " 332r 1.0078662e+05 2.43e+02 1.46e+02 -1.5 6.27e+02 - 1.00e+00 6.63e-01h 1\n", + " 333r 1.0169690e+05 9.17e+01 9.25e+01 -1.5 1.53e+02 - 1.00e+00 7.05e-01h 1\n", + " 334r 1.0207081e+05 2.83e+00 2.90e+00 -1.5 3.21e+01 - 1.00e+00 1.00e+00h 1\n", + " 335r 1.0207272e+05 1.92e-01 6.60e-02 -1.5 8.17e+00 - 1.00e+00 1.00e+00h 1\n", + " 336r 1.0210277e+05 2.14e+02 1.11e+02 -2.2 5.08e+00 - 1.00e+00 9.77e-01f 1\n", + " 337r 1.0356247e+05 1.01e+03 5.29e+02 -2.2 5.28e+02 - 4.61e-01 2.44e-01h 1\n", + " 338r 1.0508487e+05 2.49e+03 4.03e+03 -2.2 3.97e+02 - 1.00e+00 3.31e-01h 1\n", + " 339r 1.0815887e+05 1.05e+03 6.46e+02 -2.2 2.67e+02 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 340r 1.0790832e+05 9.75e+01 1.58e+01 -2.2 2.29e+01 - 1.00e+00 1.00e+00h 1\n", + " 341r 1.0799170e+05 2.00e+01 1.12e+00 -2.2 7.74e+00 - 1.00e+00 1.00e+00h 1\n", + " 342r 1.0799969e+05 1.96e-01 1.83e-02 -2.2 7.42e-01 - 1.00e+00 1.00e+00h 1\n", + " 343r 1.0799977e+05 1.96e-01 1.39e-06 -2.2 6.97e-03 - 1.00e+00 1.00e+00h 1\n", + " 344r 1.0810014e+05 1.22e+00 2.91e+02 -5.0 2.10e+01 - 8.95e-01 4.72e-01f 1\n", + " 345r 1.0810406e+05 4.81e+00 2.50e+02 -5.0 8.05e-01 -2.0 3.48e-01 4.35e-01h 1\n", + " 346r 1.0823331e+05 4.73e+00 3.13e+02 -5.0 6.45e+03 - 2.53e-01 1.89e-02f 1\n", + " 347r 1.0723140e+05 1.69e+02 4.34e+02 -5.0 1.58e+03 - 3.99e-03 4.40e-01h 1\n", + " 348r 1.0742343e+05 1.63e+02 3.79e+02 -5.0 1.51e+03 - 6.57e-01 6.72e-02h 1\n", + " 349r 1.0834320e+05 2.55e+02 5.98e+02 -5.0 1.45e+03 - 1.56e-01 3.47e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 350r 1.0905675e+05 4.18e+02 9.23e+02 -5.0 1.03e+03 - 2.62e-02 7.65e-01h 1\n", + " 351r 1.1388747e+05 2.64e+03 2.51e+03 -5.0 1.45e+03 - 2.53e-01 6.38e-01h 1\n", + " 352r 1.1388763e+05 1.74e+03 4.40e+03 -5.0 7.03e-01 -2.5 8.02e-01 3.41e-01h 1\n", + " 353r 1.1388766e+05 1.73e+03 6.62e+03 -5.0 5.05e-01 -3.0 9.72e-01 9.80e-03h 1\n", + " 354r 1.1417543e+05 1.41e+03 5.38e+03 -5.0 7.36e+02 - 4.04e-02 1.84e-01h 1\n", + " 355r 1.1417550e+05 1.40e+03 5.61e+03 -5.0 1.38e+00 -3.4 1.00e+00 3.66e-03h 1\n", + " 356r 1.1550772e+05 4.07e+02 1.18e+03 -5.0 7.26e+02 - 4.25e-02 8.35e-01h 1\n", + " 357r 1.1552641e+05 2.23e+02 7.45e+02 -5.0 4.56e+00 -3.9 6.30e-01 4.52e-01h 1\n", + " 358r 1.1558163e+05 1.25e+02 4.23e+02 -5.0 1.37e+01 -4.4 9.96e-02 4.40e-01h 1\n", + " 359r 1.1577336e+05 1.09e+02 5.76e+02 -5.0 4.44e+01 -4.9 7.36e-02 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 360r 1.1577561e+05 2.45e+03 5.78e+02 -5.0 7.08e+00 -2.6 1.51e-01 1.00e+00h 1\n", + " 361r 1.1577726e+05 1.89e+03 2.65e+02 -5.0 4.00e+00 -3.1 7.58e-01 2.50e-01h 3\n", + " 362r 1.1578214e+05 1.53e+03 1.98e+02 -5.0 5.80e+00 -3.6 3.32e-01 2.50e-01h 3\n", + " 363r 1.1578330e+05 1.50e+03 1.65e+02 -5.0 8.12e+00 -4.1 1.00e+00 2.01e-02h 6\n", + " 364r 1.1578639e+05 1.48e+03 1.42e+02 -5.0 1.72e+01 -4.5 4.68e-01 1.80e-02h 6\n", + " 365r 1.1592763e+05 1.40e+03 1.17e+02 -5.0 5.18e+01 -5.0 5.33e-01 2.75e-01h 2\n", + " 366r 1.1617094e+05 1.53e+03 9.71e+01 -5.0 1.50e+02 -5.5 1.75e-01 1.67e-01h 1\n", + " 367r 1.1703261e+05 1.26e+03 8.04e+01 -5.0 5.54e+02 -6.0 3.66e-01 1.80e-01h 1\n", + " 368r 1.2972938e+05 4.18e+03 1.66e+02 -5.0 2.79e+03 -6.4 2.07e-01 7.16e-01h 1\n", + " 369r 1.2972954e+05 4.18e+03 3.20e+02 -5.0 8.11e+02 -6.0 3.98e-01 3.44e-05h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 370r 1.2975480e+05 4.04e+03 5.38e+02 -5.0 1.31e+02 -3.8 1.19e-02 3.23e-02h 1\n", + " 371r 1.2964740e+05 3.38e+03 4.90e+02 -5.0 1.09e+02 -4.3 1.67e-03 1.64e-01h 1\n", + " 372r 1.2966158e+05 2.40e+03 3.46e+02 -5.0 7.46e+00 -3.8 2.68e-01 2.91e-01h 1\n", + " 373r 1.2973030e+05 1.27e+03 1.84e+02 -5.0 2.25e+01 -4.3 1.00e+00 4.68e-01h 1\n", + " 374r 1.3017019e+05 5.33e+01 4.05e+02 -5.0 6.82e+01 -4.8 3.63e-01 1.00e+00h 1\n", + " 375r 1.3028200e+05 5.05e+01 3.67e+02 -5.0 2.24e+02 -5.3 1.06e-01 7.97e-02h 1\n", + " 376r 1.3069758e+05 4.92e+01 3.93e+02 -5.0 8.09e+02 -5.7 4.51e-02 7.81e-02h 1\n", + " 377r 1.3069758e+05 4.92e+01 3.90e+02 -5.0 2.98e+03 - 1.65e-02 3.13e-05h 7\n", + " 378r 1.3069919e+05 4.92e+01 4.31e+02 -5.0 1.68e+03 - 1.08e-01 3.30e-04h 5\n", + " 379r 1.3126228e+05 4.78e+01 4.36e+02 -5.0 9.27e+02 - 1.70e-01 7.48e-02h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 380r 1.3306851e+05 3.73e+01 4.13e+02 -5.0 9.00e+02 - 4.51e-01 2.48e-01h 1\n", + " 381r 1.3831309e+05 1.63e+02 4.11e+02 -5.0 6.80e+02 - 1.96e-01 9.55e-01h 1\n", + " 382r 1.3831686e+05 1.59e+02 4.88e+02 -5.0 2.62e+01 - 1.36e-02 2.42e-02h 1\n", + " 383r 1.3854324e+05 2.37e+01 6.34e+02 -5.0 2.99e+01 - 3.17e-01 9.37e-01H 1\n", + " 384r 1.3854435e+05 2.30e+01 5.98e+02 -5.0 1.92e+01 - 3.14e-02 6.34e-02h 1\n", + " 385r 1.3855788e+05 1.90e+02 3.37e+02 -5.0 1.61e+01 - 6.68e-01 1.00e+00h 1\n", + " 386r 1.3855814e+05 3.75e+00 1.12e+01 -5.0 9.39e-02 - 9.55e-01 1.00e+00h 1\n", + " 387r 1.3855815e+05 4.13e+00 6.63e+02 -5.0 1.20e+00 - 3.35e-01 1.68e-01H 1\n", + " 388r 1.3855831e+05 1.34e+02 1.92e+01 -5.0 8.03e-01 - 1.00e+00 1.00e+00h 1\n", + " 389r 1.3855837e+05 9.15e+00 1.46e+00 -5.0 1.61e-01 - 1.00e+00 1.00e+00h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 390r 1.3855836e+05 2.45e-01 1.28e+00 -5.0 2.43e-02 - 1.00e+00 1.00e+00h 1\n", + " 391r 1.3855836e+05 2.45e-01 3.53e-02 -5.0 1.11e-03 - 1.00e+00 1.00e+00h 1\n", + " 392r 1.3855836e+05 2.45e-01 1.21e-06 -5.0 2.41e-05 - 1.00e+00 1.00e+00h 1\n", + " 393r 1.3855744e+05 2.08e+01 5.23e+02 -7.5 5.05e-01 - 8.64e-01 7.40e-01f 1\n", + " 394r 1.3855744e+05 1.51e+01 9.25e+02 -7.5 1.29e+00 - 2.87e-01 3.84e-01h 1\n", + " 395r 1.3855750e+05 8.64e+00 8.72e+02 -7.5 6.46e-01 - 4.26e-01 4.61e-01h 1\n", + " 396r 1.3855752e+05 4.84e+00 4.49e+02 -7.5 3.22e-01 - 6.28e-01 6.53e-01h 1\n", + " 397r 1.3855749e+05 3.20e+00 4.97e+02 -7.5 1.50e-01 - 2.97e-01 4.40e-01h 1\n", + " 398r 1.3855747e+05 1.96e+00 6.90e+02 -7.5 3.00e-02 -2.6 4.68e-02 3.88e-01h 1\n", + " 399r 1.3855745e+05 5.42e-01 5.37e+02 -7.5 2.62e-02 -3.1 3.97e-01 7.24e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 400r 1.3855744e+05 4.46e-01 3.86e+02 -7.5 2.77e-02 -2.7 2.69e-01 1.80e-01h 1\n", + " 401r 1.3855744e+05 4.34e-01 5.63e+02 -7.5 1.66e-01 -3.1 2.98e-01 2.76e-02h 1\n", + " 402r 1.3855738e+05 4.70e+00 6.16e+02 -7.5 6.32e-01 - 1.00e+00 2.87e-01h 1\n", + " 403r 1.3855735e+05 5.14e+00 3.38e+02 -7.5 3.82e-01 - 1.00e+00 2.07e-01h 1\n", + " 404r 1.3855722e+05 1.35e+01 1.78e+00 -7.5 2.46e-01 - 1.00e+00 1.00e+00h 1\n", + " 405r 1.3855722e+05 2.45e-01 1.38e-02 -7.5 1.58e-02 - 1.00e+00 1.00e+00h 1\n", + " 406r 1.3855722e+05 2.45e-01 2.29e-04 -7.5 3.59e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 406\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 1.3855721777671148e+05 1.3855721777671148e+05\n", + "Dual infeasibility......: 6.9379110321402369e+00 6.9379110321402369e+00\n", + "Constraint violation....: 2.4525985132130276e-01 2.4525985132130276e-01\n", + "Complementarity.........: 3.1231128787715433e-08 3.1231128787715433e-08\n", + "Overall NLP error.......: 6.9379110321402369e+00 6.9379110321402369e+00\n", + "\n", + "\n", + "Number of objective function evaluations = 723\n", + "Number of objective gradient evaluations = 182\n", + "Number of equality constraint evaluations = 723\n", + "Number of inequality constraint evaluations = 723\n", + "Number of equality constraint Jacobian evaluations = 446\n", + "Number of inequality constraint Jacobian evaluations = 446\n", + "Number of Lagrangian Hessian evaluations = 407\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.635\n", + "Total CPU secs in NLP function evaluations = 0.068\n", + "\n", + "EXIT: Converged to a point of local infeasibility. Problem may be infeasible.\n" + ] + } + ], "source": [ "results = solver.solve(m, tee=True)" ] @@ -1275,16 +4822,107 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 62, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 138557.21777671148\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -0.0040595 : watt : False : (None, None)\n", + " Pressure Change : -2.4174e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 4.8078e-08 - - \n", + " Total Molar Flowrate Vap mole / second 1.0000e-08 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 0.91034 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 0.089660 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 0.95213 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 0.041932 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 0.0029849 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 0.0029553 - - \n", + " Temperature kelvin 432.09 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 8.7385e-09 \n", + " flow_mol_phase Vap mole / second - 1.0000e-12 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.67175 0.67175 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.32825 0.32825 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.47214 0.47214 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.085798 0.085798 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.22083 0.22083 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.22124 0.22124 \n", + " temperature kelvin - 344.53 344.53 \n", + " pressure pascal - 1.0826e+05 1.0826e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8462216452944548\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -36576. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate Liq mole / second 0.17702 - - \n", + " Total Molar Flowrate Vap mole / second 0.068244 - - \n", + " Total Mole Fraction ('Liq', 'benzene') dimensionless 1.1730e-07 - - \n", + " Total Mole Fraction ('Liq', 'toluene') dimensionless 1.0000 - - \n", + " Total Mole Fraction ('Vap', 'benzene') dimensionless 2.4279e-07 - - \n", + " Total Mole Fraction ('Vap', 'toluene') dimensionless 1.0000 - - \n", + " Total Mole Fraction ('Vap', 'hydrogen') dimensionless 1.0000e-20 - - \n", + " Total Mole Fraction ('Vap', 'methane') dimensionless 1.0000e-20 - - \n", + " Temperature kelvin 800.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 4.8078e-08 \n", + " flow_mol_phase Vap mole / second - 1.0000e-12 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.91034 0.91034 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.089660 0.089660 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.95213 0.95213 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.041932 0.041932 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.0029849 0.0029849 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.0029553 0.0029553 \n", + " temperature kelvin - 432.09 432.09 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1310,32 +4948,47 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 63, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 800.000 K\n", + "\n", + "F101 outlet temperature = 432.088 K\n", + "\n", + "F102 outlet temperature = 344.531 K\n", + "F102 outlet pressure = 108260.028 Pa\n", + "\n" + ] + } + ], "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -1355,7 +5008,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb index bcdc90bb..e8169a6a 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_exercise.ipynb @@ -2,18 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -23,7 +25,9 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "markdown", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
      \n", + "Maintainer: Tanner Polley
      \n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
      \n", + "     2 Building a Model
      \n", + "     3 Scaling the Model
      \n", + "     4 Specifying the Model
      \n", + "     5 Initializing the Model
      \n", + "     6 Solving the Model
      \n", + "     7 Analyzing and Visualizing the Results
      \n", + "     8 Optimizing the Model
      \n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,14 +114,17 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -110,40 +132,51 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", "from pyomo.network import Arc, SequentialDecomposition" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "source": [ "from idaes.core import FlowsheetBlock" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -151,8 +184,14 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" - ] + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,16 +205,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.952476Z", + "start_time": "2025-11-20T21:46:09.949367Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ] + ], + "outputs": [], + "execution_count": 5 }, { "cell_type": "markdown", @@ -186,24 +229,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" - ] + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -218,33 +264,49 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" - ] + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -255,34 +317,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -290,11 +364,17 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
      \n", "Inline Exercise:\n", @@ -311,16 +391,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.121709Z", + "start_time": "2025-11-20T21:46:10.119134Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "markdown", @@ -336,29 +420,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -378,52 +470,97 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "![](HDA_flowsheet.png) \n", - "\n", + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, + "source": [ "
      \n", "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
      \n", - "\n" + "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide.\n", + "
      " ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.245319Z", + "start_time": "2025-11-20T21:46:10.239913Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "markdown", @@ -434,17 +571,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, { "cell_type": "markdown", "metadata": {}, @@ -454,20 +619,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -481,18 +651,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "markdown", @@ -503,14 +682,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -527,14 +711,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -545,64 +734,94 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" - ] + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
        \n", "
      • FH2 = 0.30 mol/s
      • \n", "
      • FCH4 = 0.02 mol/s
      • \n", @@ -615,39 +834,59 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" - ] + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ] + ], + "outputs": [], + "execution_count": 31 }, { "cell_type": "markdown", @@ -658,23 +897,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ] + ], + "outputs": [], + "execution_count": 32 }, { "cell_type": "markdown", @@ -685,17 +932,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ] + ], + "outputs": [], + "execution_count": 33 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -711,16 +967,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.472509Z", + "start_time": "2025-11-20T21:46:10.467229Z" + } }, - "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ] + ], + "outputs": [], + "execution_count": 34 }, { "cell_type": "markdown", @@ -731,17 +991,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ] + ], + "outputs": [], + "execution_count": 36 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -753,41 +1022,58 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.503512Z", + "start_time": "2025-11-20T21:46:10.495838Z" + } }, - "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ] + ], + "outputs": [], + "execution_count": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", "\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", "\n", - "![](HDA_flowsheet.png) \n" + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", + "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", + "\n", + "\n", + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "source": [ "seq = SequentialDecomposition()\n", "seq.options.select_tear_method = \"heuristic\"\n", @@ -798,7 +1084,9 @@ "G = seq.create_graph(m)\n", "heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", "order = seq.calculation_order(G)" - ] + ], + "outputs": [], + "execution_count": 40 }, { "cell_type": "markdown", @@ -809,13 +1097,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, + "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], + "execution_count": 41 }, { "cell_type": "markdown", @@ -826,15 +1127,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + } }, - "outputs": [], "source": [ "for o in order:\n", " print(o[0].name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], + "execution_count": 42 }, { "cell_type": "markdown", @@ -845,25 +1163,30 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -871,7 +1194,9 @@ "\n", "# Pass the tear_guess to the SD tool\n", "seq.set_guesses_for(m.fs.H101.inlet, tear_guesses)" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "markdown", @@ -882,9 +1207,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "source": [ "def function(unit):\n", " try:\n", @@ -893,7 +1221,9 @@ " except InitializationError:\n", " solver = get_solver()\n", " solver.solve(unit)" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "markdown", @@ -904,99 +1234,1132 @@ }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "source": "seq.run(m, function)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "execution_count": 45 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, + "source": [ + "from idaes.core.util.initialization import propagate_state" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", + "\n", + "We will first ensure that are current degrees of freedom is still zero" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "source": "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")", + "outputs": [], + "execution_count": 47 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ], + "outputs": [], + "execution_count": 48 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ], + "outputs": [], + "execution_count": 49 + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ], "outputs": [], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "seq.run(m, function)" + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.35e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.07e+03 1.08e+01 -1.0 1.21e+03 - 8.49e-01 6.80e-01h 1\n", + " 2 0.0000000e+00 1.66e+02 4.55e+02 -1.0 7.65e+02 - 9.90e-01 8.44e-01h 1\n", + " 3 0.0000000e+00 5.53e+00 2.00e+02 -1.0 1.30e+02 - 9.90e-01 9.67e-01h 1\n", + " 4 0.0000000e+00 5.22e-02 8.91e+03 -1.0 4.05e+00 - 1.00e+00 9.91e-01h 1\n", + " 5 0.0000000e+00 1.46e-04 1.02e+04 -1.0 3.80e-02 - 1.00e+00 9.97e-01h 1\n", + " 6 0.0000000e+00 9.46e-11 6.27e-01 -1.0 1.06e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 6\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 7\n", + "Number of objective gradient evaluations = 7\n", + "Number of equality constraint evaluations = 7\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 7\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 6\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.009\n", + "Total CPU secs in NLP function evaluations = 0.001\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 51 + }, { "cell_type": "markdown", "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", + "Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", + "\n", + "solver = get_solver(solver_options=optarg)
        \n", "results = solver.solve(m, tee=True)\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
        \n", - "\n" + "Use Shift+Enter to run the cell once you have typed in your code.\n", + "
        \n" ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.285774Z", + "start_time": "2025-11-20T21:46:17.281657Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", "\n", - "\n", "# Solve the model" - ] + ], + "outputs": [], + "execution_count": 54 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", + "## 7 Analyze the results\n", "\n", - "\n", - "What is the total operating cost? " + "\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "noauto" + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.403453Z", + "start_time": "2025-11-20T21:46:17.400372Z" + } + }, + "source": [ + "# m.fs.visualize(\"HDA-Flowsheet\")" + ], "outputs": [], + "execution_count": 57 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate mole / second 0.30005 0.32004 2.0320 2.0320 2.0320 1.7648 0.26712 1.4119 1.4119 0.17224 0.094878 0.35297\n", + " Total Mole Fraction benzene dimensionless 6.6656e-05 6.2492e-05 0.058732 0.058732 0.17408 0.084499 0.76595 0.084499 0.084499 0.82430 0.66001 0.084499\n", + " Total Mole Fraction toluene dimensionless 0.99987 6.2492e-05 0.15380 0.15380 0.038450 0.0088437 0.23405 0.0088437 0.0088437 0.17570 0.33999 0.0088437\n", + " Total Mole Fraction hydrogen dimensionless 3.3328e-05 0.93738 0.27683 0.27683 0.16148 0.18592 6.9600e-09 0.18592 0.18592 1.0794e-08 1.1376e-15 0.18592\n", + " Total Mole Fraction methane dimensionless 3.3328e-05 0.062492 0.51064 0.51064 0.62599 0.72074 2.6982e-08 0.72074 0.72074 4.1844e-08 4.4103e-15 0.72074\n", + " Temperature kelvin 303.20 303.20 324.54 600.00 822.07 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 58 + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "What is the total operating cost?" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 424513.9640158265\n" + ] + } + ], + "execution_count": 59 + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], + "source": [ + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, "source": [ "m.fs.F102.report()\n", "\n", "print()\n", "print(\"benzene purity = \", value(m.fs.purity))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.0 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.26712 - - \n", + " Total Mole Fraction benzene dimensionless 0.76595 - - \n", + " Total Mole Fraction toluene dimensionless 0.23405 - - \n", + " Total Mole Fraction hydrogen dimensionless 6.9600e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.6982e-08 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555956\n" + ] + } + ], + "execution_count": 61 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
        \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
        \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1005,25 +2368,30 @@ "\n", "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
        \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
        \n" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate mole / second 2.0320 1.7648 \n", + "Total Mole Fraction benzene dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction toluene dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction hydrogen dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction methane dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 822.07 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1050,12 +2418,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] + ], + "outputs": [], + "execution_count": 64 }, { "cell_type": "markdown", @@ -1066,19 +2439,28 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ] + ], + "outputs": [], + "execution_count": 65 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -1091,16 +2473,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.707409Z", + "start_time": "2025-11-20T21:46:17.704141Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ] + ], + "outputs": [], + "execution_count": 66 }, { "cell_type": "markdown", @@ -1119,17 +2505,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ] + ], + "outputs": [], + "execution_count": 69 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -1141,16 +2536,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.797044Z", + "start_time": "2025-11-20T21:46:17.794614Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature" - ] + ], + "outputs": [], + "execution_count": 70 }, { "cell_type": "markdown", @@ -1161,9 +2560,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)\n", @@ -1171,7 +2573,9 @@ "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] + ], + "outputs": [], + "execution_count": 72 }, { "cell_type": "markdown", @@ -1182,19 +2586,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ] + ], + "outputs": [], + "execution_count": 73 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -1206,16 +2622,20 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.862411Z", + "start_time": "2025-11-20T21:46:17.859385Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ] + ], + "outputs": [], + "execution_count": 74 }, { "cell_type": "markdown", @@ -1226,12 +2646,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] + ], + "outputs": [], + "execution_count": 76 }, { "cell_type": "markdown", @@ -1245,27 +2670,141 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, "source": [ "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 151\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 4.2451396e+05 4.00e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 4.2182392e+05 4.00e+04 6.94e+00 -1.0 3.47e+07 - 3.71e-05 1.25e-05f 1\n", + " 2 4.2170773e+05 4.00e+04 8.41e+01 -1.0 1.49e+06 - 3.32e-04 1.53e-05f 1\n", + " 3 4.1795462e+05 4.00e+04 6.82e+01 -1.0 1.43e+06 - 4.98e-04 5.60e-04f 1\n", + " 4 3.0650178e+05 4.00e+04 3.09e+02 -1.0 1.26e+07 - 2.61e-05 1.17e-03f 1\n", + " 5 3.0553183e+05 3.99e+04 3.25e+04 -1.0 1.48e+05 - 1.28e-01 1.02e-03f 1\n", + " 6 3.0565526e+05 3.91e+04 5.25e+04 -1.0 3.99e+04 - 1.13e-01 2.09e-02h 2\n", + " 7 3.0601574e+05 3.59e+04 4.21e+04 -1.0 3.91e+04 - 5.17e-02 8.21e-02h 2\n", + " 8 3.0674242e+05 2.95e+04 8.41e+04 -1.0 3.59e+04 - 4.38e-01 1.79e-01h 1\n", + " 9 3.1153051e+05 1.11e+04 5.73e+04 -1.0 2.95e+04 - 8.56e-01 6.23e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 3.1154545e+05 1.09e+04 5.69e+04 -1.0 1.19e+04 - 6.57e-02 2.37e-02h 1\n", + " 11 3.1159568e+05 1.08e+04 5.66e+04 -1.0 1.68e+04 - 2.23e-02 8.97e-03h 1\n", + " 12 3.1610911e+05 2.56e+03 2.13e+05 -1.0 1.68e+04 - 9.47e-01 7.94e-01h 1\n", + " 13 3.1708718e+05 1.16e+03 9.56e+04 -1.0 4.45e+03 - 9.90e-01 5.53e-01h 1\n", + " 14 3.1796760e+05 4.06e+02 1.14e+03 -1.0 1.27e+04 - 9.95e-01 9.87e-01h 1\n", + " 15 3.1802429e+05 5.35e+00 6.53e+02 -1.0 8.29e+01 - 1.00e+00 9.89e-01h 1\n", + " 16 3.1802524e+05 1.77e-04 5.89e+02 -1.0 5.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 17 3.1802492e+05 5.34e-06 1.83e+06 -2.5 1.32e+00 - 3.33e-01 1.00e+00f 1\n", + " 18 3.1802492e+05 1.70e-09 9.74e-03 -2.5 2.42e-02 - 1.00e+00 1.00e+00h 1\n", + " 19 3.1802491e+05 4.41e-09 1.03e-01 -5.7 3.83e-02 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 3.1802491e+05 2.39e-03 8.22e-09 -5.7 2.88e+01 - 1.00e+00 1.00e+00h 1\n", + " 21 3.1802491e+05 8.00e-11 9.72e-09 -5.7 4.08e-04 - 1.00e+00 1.00e+00h 1\n", + " 22 3.1802491e+05 2.47e-03 1.19e-01 -8.6 2.93e+01 - 9.99e-01 1.00e+00h 1\n", + " 23 3.1802491e+05 2.41e+02 2.13e-09 -8.6 9.27e+03 - 1.00e+00 1.00e+00h 1\n", + " 24 3.1802491e+05 6.96e-03 3.66e-09 -8.6 1.88e+02 - 1.00e+00 1.00e+00h 1\n", + " 25 3.1802491e+05 3.61e-06 1.59e-09 -8.6 1.21e+00 - 1.00e+00 1.00e+00h 1\n", + " 26 3.1802491e+05 2.29e-05 4.82e-09 -8.6 3.07e+00 - 1.00e+00 1.00e+00h 1\n", + " 27 3.1802491e+05 9.42e-07 5.47e-09 -8.6 6.24e-01 - 1.00e+00 1.00e+00h 1\n", + " 28 3.1802491e+05 1.16e-10 9.67e-09 -8.6 3.01e+00 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 28\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 3.1802490940142004e+05 3.1802490940142004e+05\n", + "Dual infeasibility......: 9.6706583658121551e-09 9.6706583658121551e-09\n", + "Constraint violation....: 1.1641532182693481e-10 1.1641532182693481e-10\n", + "Complementarity.........: 2.5059899579272651e-09 2.5059899579272651e-09\n", + "Overall NLP error.......: 2.2246107350021195e-10 9.6706583658121551e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 35\n", + "Number of objective gradient evaluations = 29\n", + "Number of equality constraint evaluations = 35\n", + "Number of inequality constraint evaluations = 35\n", + "Number of equality constraint Jacobian evaluations = 29\n", + "Number of inequality constraint Jacobian evaluations = 29\n", + "Number of Lagrangian Hessian evaluations = 28\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.036\n", + "Total CPU secs in NLP function evaluations = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1280,7 +2819,89 @@ "print()\n", "print(\"Overhead loss in F101\")\n", "m.fs.F101.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 318024.90940142004\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8369.3 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.28812 - - \n", + " Total Mole Fraction benzene dimensionless 0.75463 - - \n", + " Total Mole Fraction toluene dimensionless 0.24537 - - \n", + " Total Mole Fraction hydrogen dimensionless 7.5018e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.5957e-08 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8188295888411846\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -66423. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 1.9480 - - \n", + " Total Mole Fraction benzene dimensionless 0.13952 - - \n", + " Total Mole Fraction toluene dimensionless 0.039059 - - \n", + " Total Mole Fraction hydrogen dimensionless 0.18417 - - \n", + " Total Mole Fraction methane dimensionless 0.63725 - - \n", + " Temperature kelvin 763.51 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 79 }, { "cell_type": "markdown", @@ -1291,32 +2912,47 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 763.507 K\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 81 } ], "metadata": { @@ -1336,7 +2972,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb index 6f8b47f4..5f2b6695 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_solution.ipynb @@ -2,18 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -23,7 +25,9 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "markdown", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
        \n", + "Maintainer: Tanner Polley
        \n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
        \n", + "     2 Building a Model
        \n", + "     3 Scaling the Model
        \n", + "     4 Specifying the Model
        \n", + "     5 Initializing the Model
        \n", + "     6 Solving the Model
        \n", + "     7 Analyzing and Visualizing the Results
        \n", + "     8 Optimizing the Model
        \n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,14 +114,17 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -110,40 +132,51 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", "from pyomo.network import Arc, SequentialDecomposition" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "source": [ "from idaes.core import FlowsheetBlock" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -151,8 +184,14 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" - ] + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,30 +205,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.952476Z", + "start_time": "2025-11-20T21:46:09.949367Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ] + ], + "outputs": [], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.963041Z", + "start_time": "2025-11-20T21:46:09.957319Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "markdown", @@ -200,24 +247,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" - ] + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -232,33 +282,49 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" - ] + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -269,34 +335,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -304,11 +382,17 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
        \n", "Inline Exercise:\n", @@ -325,26 +409,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.121709Z", + "start_time": "2025-11-20T21:46:10.119134Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.145853Z", + "start_time": "2025-11-20T21:46:10.127921Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -354,7 +444,9 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ] + ], + "outputs": [], + "execution_count": 13 }, { "cell_type": "markdown", @@ -370,29 +462,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -412,66 +512,115 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "![](HDA_flowsheet.png) \n", - "\n", + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, + "source": [ "
        \n", "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
        \n", - "\n" + "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide.\n", + "
        " ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.245319Z", + "start_time": "2025-11-20T21:46:10.239913Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.254153Z", + "start_time": "2025-11-20T21:46:10.248481Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ] + ], + "outputs": [], + "execution_count": 19 }, { "cell_type": "markdown", @@ -482,17 +631,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, { "cell_type": "markdown", "metadata": {}, @@ -502,20 +679,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -529,18 +711,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "markdown", @@ -551,14 +742,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -575,14 +771,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -593,64 +794,94 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" - ] + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
          \n", "
        • FH2 = 0.30 mol/s
        • \n", "
        • FCH4 = 0.02 mol/s
        • \n", @@ -663,39 +894,59 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" - ] + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ] + ], + "outputs": [], + "execution_count": 31 }, { "cell_type": "markdown", @@ -706,23 +957,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ] + ], + "outputs": [], + "execution_count": 32 }, { "cell_type": "markdown", @@ -733,17 +992,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ] + ], + "outputs": [], + "execution_count": 33 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", @@ -759,30 +1027,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.472509Z", + "start_time": "2025-11-20T21:46:10.467229Z" + } }, - "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ] + ], + "outputs": [], + "execution_count": 34 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.482109Z", + "start_time": "2025-11-20T21:46:10.475567Z" + } }, - "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ] + ], + "outputs": [], + "execution_count": 35 }, { "cell_type": "markdown", @@ -793,17 +1069,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ] + ], + "outputs": [], + "execution_count": 36 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", @@ -815,54 +1100,83 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.503512Z", + "start_time": "2025-11-20T21:46:10.495838Z" + } }, - "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ] + ], + "outputs": [], + "execution_count": 37 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.535421Z", + "start_time": "2025-11-20T21:46:10.507798Z" + } }, - "outputs": [], "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", + "\n", + "\n", + "\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", "\n", - "![](HDA_flowsheet.png) \n" + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "source": [ "seq = SequentialDecomposition()\n", "seq.options.select_tear_method = \"heuristic\"\n", @@ -873,7 +1187,9 @@ "G = seq.create_graph(m)\n", "heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", "order = seq.calculation_order(G)" - ] + ], + "outputs": [], + "execution_count": 40 }, { "cell_type": "markdown", @@ -884,13 +1200,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], + "execution_count": 41 }, { "cell_type": "markdown", @@ -901,15 +1230,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + } }, - "outputs": [], "source": [ "for o in order:\n", " print(o[0].name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], + "execution_count": 42 }, { "cell_type": "markdown", @@ -920,25 +1266,30 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -946,7 +1297,9 @@ "\n", "# Pass the tear_guess to the SD tool\n", "seq.set_guesses_for(m.fs.H101.inlet, tear_guesses)" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "markdown", @@ -957,9 +1310,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "source": [ "def function(unit):\n", " try:\n", @@ -968,7 +1324,9 @@ " except InitializationError:\n", " solver = get_solver()\n", " solver.solve(unit)" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "markdown", @@ -979,118 +1337,1232 @@ }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "source": "seq.run(m, function)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "execution_count": 45 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, + "source": [ + "from idaes.core.util.initialization import propagate_state" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", + "\n", + "We will first ensure that are current degrees of freedom is still zero" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "source": "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")", "outputs": [], + "execution_count": 47 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "seq.run(m, function)" + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ], + "outputs": [], + "execution_count": 48 + }, { "cell_type": "markdown", "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ], + "outputs": [], + "execution_count": 49 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ], + "outputs": [], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.35e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.07e+03 1.08e+01 -1.0 1.21e+03 - 8.49e-01 6.80e-01h 1\n", + " 2 0.0000000e+00 1.66e+02 4.55e+02 -1.0 7.65e+02 - 9.90e-01 8.44e-01h 1\n", + " 3 0.0000000e+00 5.53e+00 2.00e+02 -1.0 1.30e+02 - 9.90e-01 9.67e-01h 1\n", + " 4 0.0000000e+00 5.22e-02 8.91e+03 -1.0 4.05e+00 - 1.00e+00 9.91e-01h 1\n", + " 5 0.0000000e+00 1.46e-04 1.02e+04 -1.0 3.80e-02 - 1.00e+00 9.97e-01h 1\n", + " 6 0.0000000e+00 9.46e-11 6.27e-01 -1.0 1.06e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 6\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 7\n", + "Number of objective gradient evaluations = 7\n", + "Number of equality constraint evaluations = 7\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 7\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 6\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.009\n", + "Total CPU secs in NLP function evaluations = 0.001\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 51 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", + "Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", + "\n", + "solver = get_solver(solver_options=optarg)
          \n", "results = solver.solve(m, tee=True)\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
          \n", - "\n" + "Use Shift+Enter to run the cell once you have typed in your code.\n", + "
          \n" ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.285774Z", + "start_time": "2025-11-20T21:46:17.281657Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", "\n", - "\n", "# Solve the model" - ] + ], + "outputs": [], + "execution_count": 54 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.382669Z", + "start_time": "2025-11-20T21:46:17.293013Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.64e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.84e+01 4.18e+00 -1.0 4.14e-01 - 9.90e-01 9.89e-01h 1\n", + " 2 0.0000000e+00 1.82e-01 3.87e+00 -1.0 3.76e-01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 6.96e-04 4.53e+02 -1.0 3.70e-02 - 9.92e-01 9.96e-01h 1\n", + " 4 0.0000000e+00 4.52e-09 8.75e-01 -1.0 3.82e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 4\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 5\n", + "Number of objective gradient evaluations = 5\n", + "Number of equality constraint evaluations = 5\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 5\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 4\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.008\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 55 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", - "\n", + "## 7 Analyze the results\n", "\n", - "What is the total operating cost? " + "\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "noauto" + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.403453Z", + "start_time": "2025-11-20T21:46:17.400372Z" + } + }, + "source": [ + "# m.fs.visualize(\"HDA-Flowsheet\")" + ], "outputs": [], + "execution_count": 57 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate mole / second 0.30005 0.32004 2.0320 2.0320 2.0320 1.7648 0.26712 1.4119 1.4119 0.17224 0.094878 0.35297\n", + " Total Mole Fraction benzene dimensionless 6.6656e-05 6.2492e-05 0.058732 0.058732 0.17408 0.084499 0.76595 0.084499 0.084499 0.82430 0.66001 0.084499\n", + " Total Mole Fraction toluene dimensionless 0.99987 6.2492e-05 0.15380 0.15380 0.038450 0.0088437 0.23405 0.0088437 0.0088437 0.17570 0.33999 0.0088437\n", + " Total Mole Fraction hydrogen dimensionless 3.3328e-05 0.93738 0.27683 0.27683 0.16148 0.18592 6.9600e-09 0.18592 0.18592 1.0794e-08 1.1376e-15 0.18592\n", + " Total Mole Fraction methane dimensionless 3.3328e-05 0.062492 0.51064 0.51064 0.62599 0.72074 2.6982e-08 0.72074 0.72074 4.1844e-08 4.4103e-15 0.72074\n", + " Temperature kelvin 303.20 303.20 324.54 600.00 822.07 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 58 + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "What is the total operating cost?" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 424513.9640158265\n" + ] + } + ], + "execution_count": 59 + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], + "source": [ + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, "source": [ "m.fs.F102.report()\n", "\n", "print()\n", "print(\"benzene purity = \", value(m.fs.purity))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.0 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.26712 - - \n", + " Total Mole Fraction benzene dimensionless 0.76595 - - \n", + " Total Mole Fraction toluene dimensionless 0.23405 - - \n", + " Total Mole Fraction hydrogen dimensionless 6.9600e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.6982e-08 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555956\n" + ] + } + ], + "execution_count": 61 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
          \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
          \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1099,25 +2571,30 @@ "\n", "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
          \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
          \n" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate mole / second 2.0320 1.7648 \n", + "Total Mole Fraction benzene dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction toluene dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction hydrogen dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction methane dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 822.07 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1144,12 +2621,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] + ], + "outputs": [], + "execution_count": 64 }, { "cell_type": "markdown", @@ -1160,19 +2642,28 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ] + ], + "outputs": [], + "execution_count": 65 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", @@ -1185,30 +2676,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.707409Z", + "start_time": "2025-11-20T21:46:17.704141Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ] + ], + "outputs": [], + "execution_count": 66 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.720592Z", + "start_time": "2025-11-20T21:46:17.717532Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ] + ], + "outputs": [], + "execution_count": 67 }, { "cell_type": "markdown", @@ -1227,17 +2726,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ] + ], + "outputs": [], + "execution_count": 69 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", @@ -1249,31 +2757,39 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.797044Z", + "start_time": "2025-11-20T21:46:17.794614Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature" - ] + ], + "outputs": [], + "execution_count": 70 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.812504Z", + "start_time": "2025-11-20T21:46:17.807564Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.R101.outlet.temperature[0].setlb(600)\n", "m.fs.R101.outlet.temperature[0].setub(800)" - ] + ], + "outputs": [], + "execution_count": 71 }, { "cell_type": "markdown", @@ -1284,9 +2800,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)\n", @@ -1294,7 +2813,9 @@ "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] + ], + "outputs": [], + "execution_count": 72 }, { "cell_type": "markdown", @@ -1305,19 +2826,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ] + ], + "outputs": [], + "execution_count": 73 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
          \n", "Inline Exercise:\n", @@ -1329,32 +2862,43 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.862411Z", + "start_time": "2025-11-20T21:46:17.859385Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ] + ], + "outputs": [], + "execution_count": 74 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.876414Z", + "start_time": "2025-11-20T21:46:17.872250Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] >= 0.15\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", ")" - ] + ], + "outputs": [], + "execution_count": 75 }, { "cell_type": "markdown", @@ -1365,12 +2909,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] + ], + "outputs": [], + "execution_count": 76 }, { "cell_type": "markdown", @@ -1384,27 +2933,141 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, "source": [ "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 151\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 4.2451396e+05 4.00e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 4.2182392e+05 4.00e+04 6.94e+00 -1.0 3.47e+07 - 3.71e-05 1.25e-05f 1\n", + " 2 4.2170773e+05 4.00e+04 8.41e+01 -1.0 1.49e+06 - 3.32e-04 1.53e-05f 1\n", + " 3 4.1795462e+05 4.00e+04 6.82e+01 -1.0 1.43e+06 - 4.98e-04 5.60e-04f 1\n", + " 4 3.0650178e+05 4.00e+04 3.09e+02 -1.0 1.26e+07 - 2.61e-05 1.17e-03f 1\n", + " 5 3.0553183e+05 3.99e+04 3.25e+04 -1.0 1.48e+05 - 1.28e-01 1.02e-03f 1\n", + " 6 3.0565526e+05 3.91e+04 5.25e+04 -1.0 3.99e+04 - 1.13e-01 2.09e-02h 2\n", + " 7 3.0601574e+05 3.59e+04 4.21e+04 -1.0 3.91e+04 - 5.17e-02 8.21e-02h 2\n", + " 8 3.0674242e+05 2.95e+04 8.41e+04 -1.0 3.59e+04 - 4.38e-01 1.79e-01h 1\n", + " 9 3.1153051e+05 1.11e+04 5.73e+04 -1.0 2.95e+04 - 8.56e-01 6.23e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 3.1154545e+05 1.09e+04 5.69e+04 -1.0 1.19e+04 - 6.57e-02 2.37e-02h 1\n", + " 11 3.1159568e+05 1.08e+04 5.66e+04 -1.0 1.68e+04 - 2.23e-02 8.97e-03h 1\n", + " 12 3.1610911e+05 2.56e+03 2.13e+05 -1.0 1.68e+04 - 9.47e-01 7.94e-01h 1\n", + " 13 3.1708718e+05 1.16e+03 9.56e+04 -1.0 4.45e+03 - 9.90e-01 5.53e-01h 1\n", + " 14 3.1796760e+05 4.06e+02 1.14e+03 -1.0 1.27e+04 - 9.95e-01 9.87e-01h 1\n", + " 15 3.1802429e+05 5.35e+00 6.53e+02 -1.0 8.29e+01 - 1.00e+00 9.89e-01h 1\n", + " 16 3.1802524e+05 1.77e-04 5.89e+02 -1.0 5.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 17 3.1802492e+05 5.34e-06 1.83e+06 -2.5 1.32e+00 - 3.33e-01 1.00e+00f 1\n", + " 18 3.1802492e+05 1.70e-09 9.74e-03 -2.5 2.42e-02 - 1.00e+00 1.00e+00h 1\n", + " 19 3.1802491e+05 4.41e-09 1.03e-01 -5.7 3.83e-02 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 3.1802491e+05 2.39e-03 8.22e-09 -5.7 2.88e+01 - 1.00e+00 1.00e+00h 1\n", + " 21 3.1802491e+05 8.00e-11 9.72e-09 -5.7 4.08e-04 - 1.00e+00 1.00e+00h 1\n", + " 22 3.1802491e+05 2.47e-03 1.19e-01 -8.6 2.93e+01 - 9.99e-01 1.00e+00h 1\n", + " 23 3.1802491e+05 2.41e+02 2.13e-09 -8.6 9.27e+03 - 1.00e+00 1.00e+00h 1\n", + " 24 3.1802491e+05 6.96e-03 3.66e-09 -8.6 1.88e+02 - 1.00e+00 1.00e+00h 1\n", + " 25 3.1802491e+05 3.61e-06 1.59e-09 -8.6 1.21e+00 - 1.00e+00 1.00e+00h 1\n", + " 26 3.1802491e+05 2.29e-05 4.82e-09 -8.6 3.07e+00 - 1.00e+00 1.00e+00h 1\n", + " 27 3.1802491e+05 9.42e-07 5.47e-09 -8.6 6.24e-01 - 1.00e+00 1.00e+00h 1\n", + " 28 3.1802491e+05 1.16e-10 9.67e-09 -8.6 3.01e+00 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 28\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 3.1802490940142004e+05 3.1802490940142004e+05\n", + "Dual infeasibility......: 9.6706583658121551e-09 9.6706583658121551e-09\n", + "Constraint violation....: 1.1641532182693481e-10 1.1641532182693481e-10\n", + "Complementarity.........: 2.5059899579272651e-09 2.5059899579272651e-09\n", + "Overall NLP error.......: 2.2246107350021195e-10 9.6706583658121551e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 35\n", + "Number of objective gradient evaluations = 29\n", + "Number of equality constraint evaluations = 35\n", + "Number of inequality constraint evaluations = 35\n", + "Number of equality constraint Jacobian evaluations = 29\n", + "Number of inequality constraint Jacobian evaluations = 29\n", + "Number of Lagrangian Hessian evaluations = 28\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.036\n", + "Total CPU secs in NLP function evaluations = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1419,7 +3082,89 @@ "print()\n", "print(\"Overhead loss in F101\")\n", "m.fs.F101.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 318024.90940142004\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8369.3 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.28812 - - \n", + " Total Mole Fraction benzene dimensionless 0.75463 - - \n", + " Total Mole Fraction toluene dimensionless 0.24537 - - \n", + " Total Mole Fraction hydrogen dimensionless 7.5018e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.5957e-08 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8188295888411846\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -66423. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 1.9480 - - \n", + " Total Mole Fraction benzene dimensionless 0.13952 - - \n", + " Total Mole Fraction toluene dimensionless 0.039059 - - \n", + " Total Mole Fraction hydrogen dimensionless 0.18417 - - \n", + " Total Mole Fraction methane dimensionless 0.63725 - - \n", + " Temperature kelvin 763.51 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 79 }, { "cell_type": "markdown", @@ -1430,32 +3175,47 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 763.507 K\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 81 } ], "metadata": { @@ -1475,7 +3235,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb index 415cf48c..471da278 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_test.ipynb @@ -2,18 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -23,7 +25,9 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "markdown", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
          \n", + "Maintainer: Tanner Polley
          \n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
          \n", + "     2 Building a Model
          \n", + "     3 Scaling the Model
          \n", + "     4 Specifying the Model
          \n", + "     5 Initializing the Model
          \n", + "     6 Solving the Model
          \n", + "     7 Analyzing and Visualizing the Results
          \n", + "     8 Optimizing the Model
          \n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,14 +114,17 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -110,40 +132,51 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", "from pyomo.network import Arc, SequentialDecomposition" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "source": [ "from idaes.core import FlowsheetBlock" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -151,8 +184,14 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" - ] + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,17 +205,21 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.963041Z", + "start_time": "2025-11-20T21:46:09.957319Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "markdown", @@ -187,24 +230,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" - ] + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -219,33 +265,49 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" - ] + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -256,34 +318,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -291,34 +365,21 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
          \n", - "Inline Exercise:\n", - "Let us now add the StoichiometricReactor(assign the name R101) and pass the following arguments:\n", - "
            \n", - "
          • \"property_package\": m.fs.thermo_params
          • \n", - "
          • \"reaction_package\": m.fs.reaction_params
          • \n", - "
          • \"has_heat_of_reaction\": True
          • \n", - "
          • \"has_heat_transfer\": True
          • \n", - "
          • \"has_pressure_change\": False
          • \n", - "
          \n", - "
          " - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.145853Z", + "start_time": "2025-11-20T21:46:10.127921Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -328,7 +389,9 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ] + ], + "outputs": [], + "execution_count": 13 }, { "cell_type": "markdown", @@ -344,29 +407,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -386,53 +457,84 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "![](HDA_flowsheet.png) \n", - "\n", - "
          \n", - "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
          \n", - "\n" + "![](HDA_flowsheet.png)" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "code", "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.254153Z", + "start_time": "2025-11-20T21:46:10.248481Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ] + ], + "outputs": [], + "execution_count": 19 }, { "cell_type": "markdown", @@ -443,17 +545,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, { "cell_type": "markdown", "metadata": {}, @@ -463,20 +593,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -490,18 +625,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "markdown", @@ -512,14 +656,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -536,14 +685,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -554,78 +708,112 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.409008Z", + "start_time": "2025-11-20T21:46:10.382157Z" + } }, - "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 29" - ] + ], + "outputs": [], + "execution_count": 28 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" - ] + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
            \n", "
          • FH2 = 0.30 mol/s
          • \n", "
          • FCH4 = 0.02 mol/s
          • \n", @@ -638,39 +826,59 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" - ] + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ] + ], + "outputs": [], + "execution_count": 31 }, { "cell_type": "markdown", @@ -681,23 +889,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ] + ], + "outputs": [], + "execution_count": 32 }, { "cell_type": "markdown", @@ -708,43 +924,36 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "Set the conditions for Flash F102 to the following conditions:\n", - "
              \n", - "
            • T = 375 K
            • \n", - "
            • deltaP = -200000
            • \n", - "
            \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            " - ] + ], + "outputs": [], + "execution_count": 33 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.482109Z", + "start_time": "2025-11-20T21:46:10.475567Z" + } }, - "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ] + ], + "outputs": [], + "execution_count": 35 }, { "cell_type": "markdown", @@ -755,77 +964,99 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "We have now defined all the feed conditions and the inputs required for the unit models. The system should now have 0 degrees of freedom i.e. should be a square problem. Please check that the degrees of freedom is 0. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            " - ] + ], + "outputs": [], + "execution_count": 36 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.535421Z", + "start_time": "2025-11-20T21:46:10.507798Z" + } }, - "outputs": [], "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 38 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.568992Z", + "start_time": "2025-11-20T21:46:10.542995Z" + } }, - "outputs": [], "source": [ "# Check the degrees of freedom\n", "assert degrees_of_freedom(m) == 0" - ] + ], + "outputs": [], + "execution_count": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", + "\n", "\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", "\n", - "![](HDA_flowsheet.png) \n" + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", + "\n", + "\n", + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "source": [ "seq = SequentialDecomposition()\n", "seq.options.select_tear_method = \"heuristic\"\n", @@ -836,7 +1067,9 @@ "G = seq.create_graph(m)\n", "heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", "order = seq.calculation_order(G)" - ] + ], + "outputs": [], + "execution_count": 40 }, { "cell_type": "markdown", @@ -847,13 +1080,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], + "execution_count": 41 }, { "cell_type": "markdown", @@ -864,15 +1110,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + } }, - "outputs": [], "source": [ "for o in order:\n", " print(o[0].name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], + "execution_count": 42 }, { "cell_type": "markdown", @@ -883,25 +1146,30 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -909,7 +1177,9 @@ "\n", "# Pass the tear_guess to the SD tool\n", "seq.set_guesses_for(m.fs.H101.inlet, tear_guesses)" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "markdown", @@ -920,9 +1190,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "source": [ "def function(unit):\n", " try:\n", @@ -931,7 +1204,9 @@ " except InitializationError:\n", " solver = get_solver()\n", " solver.solve(unit)" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "markdown", @@ -942,149 +1217,1235 @@ }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "source": "seq.run(m, function)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "execution_count": 45 + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, + "source": [ + "from idaes.core.util.initialization import propagate_state" + ], "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "seq.run(m, function)" + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", + "\n", + "We will first ensure that are current degrees of freedom is still zero" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "source": "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")", + "outputs": [], + "execution_count": 47 + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "
            \n", - "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", - "results = solver.solve(m, tee=True)\n", + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ], + "outputs": [], + "execution_count": 48 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ], + "outputs": [], + "execution_count": 49 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ], + "outputs": [], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.35e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.07e+03 1.08e+01 -1.0 1.21e+03 - 8.49e-01 6.80e-01h 1\n", + " 2 0.0000000e+00 1.66e+02 4.55e+02 -1.0 7.65e+02 - 9.90e-01 8.44e-01h 1\n", + " 3 0.0000000e+00 5.53e+00 2.00e+02 -1.0 1.30e+02 - 9.90e-01 9.67e-01h 1\n", + " 4 0.0000000e+00 5.22e-02 8.91e+03 -1.0 4.05e+00 - 1.00e+00 9.91e-01h 1\n", + " 5 0.0000000e+00 1.46e-04 1.02e+04 -1.0 3.80e-02 - 1.00e+00 9.97e-01h 1\n", + " 6 0.0000000e+00 9.46e-11 6.27e-01 -1.0 1.06e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 6\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 7\n", + "Number of objective gradient evaluations = 7\n", + "Number of equality constraint evaluations = 7\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 7\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 6\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.009\n", + "Total CPU secs in NLP function evaluations = 0.001\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 51 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            \n", - "\n" + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "code", "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.382669Z", + "start_time": "2025-11-20T21:46:17.293013Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.64e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.84e+01 4.18e+00 -1.0 4.14e-01 - 9.90e-01 9.89e-01h 1\n", + " 2 0.0000000e+00 1.82e-01 3.87e+00 -1.0 3.76e-01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 6.96e-04 4.53e+02 -1.0 3.70e-02 - 9.92e-01 9.96e-01h 1\n", + " 4 0.0000000e+00 4.52e-09 8.75e-01 -1.0 3.82e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 4\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 5\n", + "Number of objective gradient evaluations = 5\n", + "Number of equality constraint evaluations = 5\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 5\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 4\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.008\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 55 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.393870Z", + "start_time": "2025-11-20T21:46:17.390132Z" + } }, - "outputs": [], "source": [ "# Check solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 56 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", - "\n", + "## 7 Analyze the results\n", "\n", - "What is the total operating cost? " + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate mole / second 0.30005 0.32004 2.0320 2.0320 2.0320 1.7648 0.26712 1.4119 1.4119 0.17224 0.094878 0.35297\n", + " Total Mole Fraction benzene dimensionless 6.6656e-05 6.2492e-05 0.058732 0.058732 0.17408 0.084499 0.76595 0.084499 0.084499 0.82430 0.66001 0.084499\n", + " Total Mole Fraction toluene dimensionless 0.99987 6.2492e-05 0.15380 0.15380 0.038450 0.0088437 0.23405 0.0088437 0.0088437 0.17570 0.33999 0.0088437\n", + " Total Mole Fraction hydrogen dimensionless 3.3328e-05 0.93738 0.27683 0.27683 0.16148 0.18592 6.9600e-09 0.18592 0.18592 1.0794e-08 1.1376e-15 0.18592\n", + " Total Mole Fraction methane dimensionless 3.3328e-05 0.062492 0.51064 0.51064 0.62599 0.72074 2.6982e-08 0.72074 0.72074 4.1844e-08 4.4103e-15 0.72074\n", + " Temperature kelvin 303.20 303.20 324.54 600.00 822.07 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 58 + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" + "What is the total operating cost?" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 424513.9640158265\n" + ] + } + ], + "execution_count": 59 + }, + { + "cell_type": "code", "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.571498Z", + "start_time": "2025-11-20T21:46:17.493194Z" + } }, - "outputs": [], "source": [ "import pytest\n", "\n", - "assert value(m.fs.operating_cost) == pytest.approx(419122.3387, abs=1e-3)" - ] + "assert value(m.fs.operating_cost) == pytest.approx(424513.9645, abs=1e-3)" + ], + "outputs": [], + "execution_count": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, "source": [ "m.fs.F102.report()\n", "\n", "print()\n", "print(\"benzene purity = \", value(m.fs.purity))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.0 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.26712 - - \n", + " Total Mole Fraction benzene dimensionless 0.76595 - - \n", + " Total Mole Fraction toluene dimensionless 0.23405 - - \n", + " Total Mole Fraction hydrogen dimensionless 6.9600e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.6982e-08 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555956\n" + ] + } + ], + "execution_count": 61 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.619054Z", + "start_time": "2025-11-20T21:46:17.613393Z" + } }, - "outputs": [], "source": [ "assert value(m.fs.purity) == pytest.approx(0.82429, abs=1e-3)\n", - "\n", - "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7352.4828, abs=1e-3)\n", + "assert value(m.fs.F102.heat_duty[0]) == pytest.approx(7346.03097, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(1.5000e05, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 62 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
            \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
            \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1093,25 +2454,30 @@ "\n", "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            \n" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate mole / second 2.0320 1.7648 \n", + "Total Mole Fraction benzene dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction toluene dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction hydrogen dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction methane dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 822.07 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1138,12 +2504,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] + ], + "outputs": [], + "execution_count": 64 }, { "cell_type": "markdown", @@ -1154,55 +2525,55 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "Let us now unfix the remaining variable which is F102 pressure drop (F102.deltaP) \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            \n", - "\n" - ] + ], + "outputs": [], + "execution_count": 65 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.720592Z", + "start_time": "2025-11-20T21:46:17.717532Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ] + ], + "outputs": [], + "execution_count": 67 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.759351Z", + "start_time": "2025-11-20T21:46:17.728327Z" + } }, - "outputs": [], "source": [ "assert degrees_of_freedom(m) == 5" - ] + ], + "outputs": [], + "execution_count": 68 }, { "cell_type": "markdown", @@ -1221,40 +2592,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "Now, set the variable bound for the R101 outlet temperature.\n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            " - ] + ], + "outputs": [], + "execution_count": 69 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.812504Z", + "start_time": "2025-11-20T21:46:17.807564Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.R101.outlet.temperature[0].setlb(600)\n", "m.fs.R101.outlet.temperature[0].setub(800)" - ] + ], + "outputs": [], + "execution_count": 71 }, { "cell_type": "markdown", @@ -1265,9 +2633,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)\n", @@ -1275,7 +2646,9 @@ "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] + ], + "outputs": [], + "execution_count": 72 }, { "cell_type": "markdown", @@ -1286,43 +2659,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
            \n", - "Inline Exercise:\n", - "Now, add the constraint such that we are producing at least 0.15 mol/s of benzene in the product stream which is the vapor outlet of F102. Let us name this constraint as m.fs.product_flow. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
            " - ] + ], + "outputs": [], + "execution_count": 73 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.876414Z", + "start_time": "2025-11-20T21:46:17.872250Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] >= 0.15\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", ")" - ] + ], + "outputs": [], + "execution_count": 75 }, { "cell_type": "markdown", @@ -1333,12 +2709,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] + ], + "outputs": [], + "execution_count": 76 }, { "cell_type": "markdown", @@ -1352,43 +2733,161 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, "source": [ "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 151\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 4.2451396e+05 4.00e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 4.2182392e+05 4.00e+04 6.94e+00 -1.0 3.47e+07 - 3.71e-05 1.25e-05f 1\n", + " 2 4.2170773e+05 4.00e+04 8.41e+01 -1.0 1.49e+06 - 3.32e-04 1.53e-05f 1\n", + " 3 4.1795462e+05 4.00e+04 6.82e+01 -1.0 1.43e+06 - 4.98e-04 5.60e-04f 1\n", + " 4 3.0650178e+05 4.00e+04 3.09e+02 -1.0 1.26e+07 - 2.61e-05 1.17e-03f 1\n", + " 5 3.0553183e+05 3.99e+04 3.25e+04 -1.0 1.48e+05 - 1.28e-01 1.02e-03f 1\n", + " 6 3.0565526e+05 3.91e+04 5.25e+04 -1.0 3.99e+04 - 1.13e-01 2.09e-02h 2\n", + " 7 3.0601574e+05 3.59e+04 4.21e+04 -1.0 3.91e+04 - 5.17e-02 8.21e-02h 2\n", + " 8 3.0674242e+05 2.95e+04 8.41e+04 -1.0 3.59e+04 - 4.38e-01 1.79e-01h 1\n", + " 9 3.1153051e+05 1.11e+04 5.73e+04 -1.0 2.95e+04 - 8.56e-01 6.23e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 3.1154545e+05 1.09e+04 5.69e+04 -1.0 1.19e+04 - 6.57e-02 2.37e-02h 1\n", + " 11 3.1159568e+05 1.08e+04 5.66e+04 -1.0 1.68e+04 - 2.23e-02 8.97e-03h 1\n", + " 12 3.1610911e+05 2.56e+03 2.13e+05 -1.0 1.68e+04 - 9.47e-01 7.94e-01h 1\n", + " 13 3.1708718e+05 1.16e+03 9.56e+04 -1.0 4.45e+03 - 9.90e-01 5.53e-01h 1\n", + " 14 3.1796760e+05 4.06e+02 1.14e+03 -1.0 1.27e+04 - 9.95e-01 9.87e-01h 1\n", + " 15 3.1802429e+05 5.35e+00 6.53e+02 -1.0 8.29e+01 - 1.00e+00 9.89e-01h 1\n", + " 16 3.1802524e+05 1.77e-04 5.89e+02 -1.0 5.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 17 3.1802492e+05 5.34e-06 1.83e+06 -2.5 1.32e+00 - 3.33e-01 1.00e+00f 1\n", + " 18 3.1802492e+05 1.70e-09 9.74e-03 -2.5 2.42e-02 - 1.00e+00 1.00e+00h 1\n", + " 19 3.1802491e+05 4.41e-09 1.03e-01 -5.7 3.83e-02 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 3.1802491e+05 2.39e-03 8.22e-09 -5.7 2.88e+01 - 1.00e+00 1.00e+00h 1\n", + " 21 3.1802491e+05 8.00e-11 9.72e-09 -5.7 4.08e-04 - 1.00e+00 1.00e+00h 1\n", + " 22 3.1802491e+05 2.47e-03 1.19e-01 -8.6 2.93e+01 - 9.99e-01 1.00e+00h 1\n", + " 23 3.1802491e+05 2.41e+02 2.13e-09 -8.6 9.27e+03 - 1.00e+00 1.00e+00h 1\n", + " 24 3.1802491e+05 6.96e-03 3.66e-09 -8.6 1.88e+02 - 1.00e+00 1.00e+00h 1\n", + " 25 3.1802491e+05 3.61e-06 1.59e-09 -8.6 1.21e+00 - 1.00e+00 1.00e+00h 1\n", + " 26 3.1802491e+05 2.29e-05 4.82e-09 -8.6 3.07e+00 - 1.00e+00 1.00e+00h 1\n", + " 27 3.1802491e+05 9.42e-07 5.47e-09 -8.6 6.24e-01 - 1.00e+00 1.00e+00h 1\n", + " 28 3.1802491e+05 1.16e-10 9.67e-09 -8.6 3.01e+00 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 28\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 3.1802490940142004e+05 3.1802490940142004e+05\n", + "Dual infeasibility......: 9.6706583658121551e-09 9.6706583658121551e-09\n", + "Constraint violation....: 1.1641532182693481e-10 1.1641532182693481e-10\n", + "Complementarity.........: 2.5059899579272651e-09 2.5059899579272651e-09\n", + "Overall NLP error.......: 2.2246107350021195e-10 9.6706583658121551e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 35\n", + "Number of objective gradient evaluations = 29\n", + "Number of equality constraint evaluations = 35\n", + "Number of inequality constraint evaluations = 35\n", + "Number of equality constraint Jacobian evaluations = 29\n", + "Number of inequality constraint Jacobian evaluations = 29\n", + "Number of Lagrangian Hessian evaluations = 28\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.036\n", + "Total CPU secs in NLP function evaluations = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 77 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.045752Z", + "start_time": "2025-11-20T21:46:18.041549Z" + } }, - "outputs": [], "source": [ "# Check for solver solve status\n", "from pyomo.environ import TerminationCondition\n", "\n", "assert results.solver.termination_condition == TerminationCondition.optimal" - ] + ], + "outputs": [], + "execution_count": 78 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1403,21 +2902,107 @@ "print()\n", "print(\"Overhead loss in F101\")\n", "m.fs.F101.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 318024.90940142004\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8369.3 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.28812 - - \n", + " Total Mole Fraction benzene dimensionless 0.75463 - - \n", + " Total Mole Fraction toluene dimensionless 0.24537 - - \n", + " Total Mole Fraction hydrogen dimensionless 7.5018e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.5957e-08 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8188295888411846\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -66423. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 1.9480 - - \n", + " Total Mole Fraction benzene dimensionless 0.13952 - - \n", + " Total Mole Fraction toluene dimensionless 0.039059 - - \n", + " Total Mole Fraction hydrogen dimensionless 0.18417 - - \n", + " Total Mole Fraction methane dimensionless 0.63725 - - \n", + " Temperature kelvin 763.51 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 79 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.093619Z", + "start_time": "2025-11-20T21:46:18.090039Z" + } }, - "outputs": [], "source": [ - "assert value(m.fs.operating_cost) == pytest.approx(312786.338, abs=1e-3)\n", + "assert value(m.fs.operating_cost) == pytest.approx(318024.909, abs=1e-3)\n", "assert value(m.fs.purity) == pytest.approx(0.818827, abs=1e-3)" - ] + ], + "outputs": [], + "execution_count": 80 }, { "cell_type": "markdown", @@ -1428,49 +3013,88 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" - ] + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 763.507 K\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 81 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "testing" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:19.262061Z", + "start_time": "2025-11-20T21:46:18.121920Z" + } }, - "outputs": [], "source": [ "assert value(m.fs.H101.outlet.temperature[0]) == pytest.approx(500, abs=1e-3)\n", - "assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(696.112, abs=1e-3)\n", - "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.878, abs=1e-3)\n", + "print(value(m.fs.R101.outlet.temperature[0]))\n", + "assert value(m.fs.R101.outlet.temperature[0]) == pytest.approx(763.484, abs=1e-3)\n", + "assert value(m.fs.F101.vap_outlet.temperature[0]) == pytest.approx(301.881, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.temperature[0]) == pytest.approx(362.935, abs=1e-3)\n", "assert value(m.fs.F102.vap_outlet.pressure[0]) == pytest.approx(105000, abs=1e-2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "763.5072359720118\n" + ] + }, + { + "ename": "AssertionError", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mAssertionError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[82]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.H101.outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m500\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 2\u001b[39m \u001b[38;5;28mprint\u001b[39m(value(m.fs.R101.outlet.temperature[\u001b[32m0\u001b[39m]))\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.R101.outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m763.484\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 4\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.F101.vap_outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m301.881\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n\u001b[32m 5\u001b[39m \u001b[38;5;28;01massert\u001b[39;00m value(m.fs.F102.vap_outlet.temperature[\u001b[32m0\u001b[39m]) == pytest.approx(\u001b[32m362.935\u001b[39m, \u001b[38;5;28mabs\u001b[39m=\u001b[32m1e-3\u001b[39m)\n", + "\u001b[31mAssertionError\u001b[39m: " + ] + } + ], + "execution_count": 82 } ], "metadata": { @@ -1490,7 +3114,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb index 6f8b47f4..5f2b6695 100644 --- a/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb +++ b/idaes_examples/notebooks/docs/tut/core/hda_flowsheet_usr.ipynb @@ -2,18 +2,20 @@ "cells": [ { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "header", "hide-cell" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:04.904828Z", + "start_time": "2025-11-20T21:46:04.900352Z" + } }, - "outputs": [], "source": [ "###############################################################################\n", "# The Institute for the Design of Advanced Energy Systems Integrated Platform\n", - "# Framework (IDAES IP) was produced under the DOE Institute for the\n", + "# Framework (idaes IP) was produced under the DOE Institute for the\n", "# Design of Advanced Energy Systems (IDAES).\n", "#\n", "# Copyright (c) 2018-2023 by the software owners: The Regents of the\n", @@ -23,7 +25,9 @@ "# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md\n", "# for full copyright and license information.\n", "###############################################################################" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "markdown", @@ -32,20 +36,34 @@ "\n", "# HDA Flowsheet Simulation and Optimization\n", "\n", - "Author: Jaffer Ghouse \n", - "Maintainer: Brandon Paul \n", - "Updated: 2023-06-01 \n", + "Author: Jaffer Ghouse
            \n", + "Maintainer: Tanner Polley
            \n", + "Updated: 2025-11-19\n", "\n", "## Learning outcomes\n", "\n", "\n", "- Construct a steady-state flowsheet using the IDAES unit model library\n", - "- Connecting unit models in a flowsheet using Arcs\n", + "- Connecting unit models in a flowsheet using Arcs\n", "- Using the SequentialDecomposition tool to initialize a flowsheet with recycle\n", - "- Fomulate and solve an optimization problem\n", + "- Formulate and solve an optimization problem\n", " - Defining an objective function\n", " - Setting variable bounds\n", - " - Adding additional constraints \n", + " - Adding additional constraints\n", + "\n", + "\n", + "The general workflow of setting up an IDAES flowsheet is the following:\n", + "\n", + "     1 Importing Modules
            \n", + "     2 Building a Model
            \n", + "     3 Scaling the Model
            \n", + "     4 Specifying the Model
            \n", + "     5 Initializing the Model
            \n", + "     6 Solving the Model
            \n", + "     7 Analyzing and Visualizing the Results
            \n", + "     8 Optimizing the Model
            \n", + "\n", + "We will complete each of these steps as well as demonstrate analyses on this model through some examples and exercises.\n", "\n", "\n", "## Problem Statement\n", @@ -81,10 +99,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required pyomo and idaes components\n", + "## 1 Importing Modules\n", + "### 1.1 Importing required Pyomo and IDAES components\n", "\n", "\n", - "To construct a flowsheet, we will need several components from the pyomo and idaes package. Let us first import the following components from Pyomo:\n", + "To construct a flowsheet, we will need several components from the Pyomo and IDAES package. Let us first import the following components from Pyomo:\n", "- Constraint (to write constraints)\n", "- Var (to declare variables)\n", "- ConcreteModel (to create the concrete model object)\n", @@ -95,14 +114,17 @@ "- Arc (to connect two unit models)\n", "- SequentialDecomposition (to initialize the flowsheet in a sequential mode)\n", "\n", - "For further details on these components, please refer to the pyomo documentation: https://pyomo.readthedocs.io/en/stable/\n" + "For further details on these components, please refer to the Pyomo documentation: https://Pyomo.readthedocs.io/en/stable/\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:05.294578Z", + "start_time": "2025-11-20T21:46:04.908296Z" + } + }, "source": [ "from pyomo.environ import (\n", " Constraint,\n", @@ -110,40 +132,51 @@ " ConcreteModel,\n", " Expression,\n", " Objective,\n", - " SolverFactory,\n", " TransformationFactory,\n", " value,\n", ")\n", "from pyomo.network import Arc, SequentialDecomposition" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "From idaes, we will be needing the FlowsheetBlock and the following unit models:\n", + "From IDAES, we will be needing the FlowsheetBlock and the following unit models:\n", + "- Feed\n", "- Mixer\n", "- Heater\n", "- StoichiometricReactor\n", "- **Flash**\n", "- Separator (splitter) \n", - "- PressureChanger" + "- PressureChanger\n", + "- Product" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:06.806301Z", + "start_time": "2025-11-20T21:46:05.297760Z" + } + }, "source": [ "from idaes.core import FlowsheetBlock" - ] + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.936732Z", + "start_time": "2025-11-20T21:46:09.883054Z" + } + }, "source": [ "from idaes.models.unit_models import (\n", " PressureChanger,\n", @@ -151,8 +184,14 @@ " Separator as Splitter,\n", " Heater,\n", " StoichiometricReactor,\n", - ")" - ] + " Feed,\n", + " Product,\n", + ")\n", + "from idaes.core.util.exceptions import InitializationError\n", + "import idaes.logger as idaeslog" + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -166,30 +205,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.952476Z", + "start_time": "2025-11-20T21:46:09.949367Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models" - ] + ], + "outputs": [], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.963041Z", + "start_time": "2025-11-20T21:46:09.957319Z" + } }, - "outputs": [], "source": [ "# Todo: import flash model from idaes.models.unit_models\n", "from idaes.models.unit_models import Flash" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "markdown", @@ -200,24 +247,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:09.976914Z", + "start_time": "2025-11-20T21:46:09.971944Z" + } + }, "source": [ "from idaes.models.unit_models.pressure_changer import ThermodynamicAssumption\n", "from idaes.core.util.model_statistics import degrees_of_freedom\n", "\n", "# Import idaes logger to set output levels\n", - "import idaes.logger as idaeslog\n", - "from idaes.core.solvers import get_solver\n", - "from idaes.core.util.exceptions import InitializationError" - ] + "from idaes.core.solvers import get_solver" + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Importing required thermo and reaction package\n", + "### 1.2 Importing required thermo and reaction package\n", "\n", "The final set of imports are to import the thermo and reaction package for the HDA process. We have created a custom thermo package that assumes Ideal Gas with support for VLE. \n", "\n", @@ -232,33 +282,49 @@ ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.017098Z", + "start_time": "2025-11-20T21:46:09.981997Z" + } + }, "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], "source": [ - "from idaes_examples.mod.hda import hda_ideal_VLE as thermo_props\n", - "from idaes_examples.mod.hda import hda_reaction as reaction_props" - ] + "from idaes.models.properties.modular_properties.base.generic_property import (\n", + " GenericParameterBlock,\n", + ")\n", + "from idaes.models.properties.modular_properties.base.generic_reaction import (\n", + " GenericReactionParameterBlock,\n", + ")\n", + "from idaes_examples.mod.hda.hda_ideal_VLE_modular import thermo_config\n", + "from idaes_examples.mod.hda.hda_reaction_modular import reaction_config" + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Constructing the Flowsheet\n", + "## 2 Constructing the Flowsheet\n", "\n", - "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block as we did in module 1. " + "We have now imported all the components, unit models, and property modules we need to construct a flowsheet. Let us create a ConcreteModel and add the flowsheet block." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.031538Z", + "start_time": "2025-11-20T21:46:10.025904Z" + } + }, "source": [ "m = ConcreteModel()\n", "m.fs = FlowsheetBlock(dynamic=False)" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "markdown", @@ -269,34 +335,46 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.066746Z", + "start_time": "2025-11-20T21:46:10.035131Z" + } + }, "source": [ - "m.fs.thermo_params = thermo_props.HDAParameterBlock()\n", - "m.fs.reaction_params = reaction_props.HDAReactionParameterBlock(\n", - " property_package=m.fs.thermo_params\n", + "m.fs.thermo_params = GenericParameterBlock(**thermo_config)\n", + "m.fs.reaction_params = GenericReactionParameterBlock(\n", + " property_package=m.fs.thermo_params, **reaction_config\n", ")" - ] + ], + "outputs": [], + "execution_count": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding Unit Models\n", + "### 2.1 Adding Unit Models\n", "\n", - "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Mixer (assigned a name M101) and a Heater (assigned a name H101). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the Mixer unit model here is given a `list` consisting of names to the three inlets. " + "Let us start adding the unit models we have imported to the flowsheet. Here, we are adding the Feed (assigned a name `I101` for Inlet), `Mixer` (assigned a name `M101`) and a `Heater` (assigned a name `H101`). Note that, all unit models need to be given a property package argument. In addition to that, there are several arguments depending on the unit model, please refer to the documentation for more details (https://idaes-pse.readthedocs.io/en/stable/reference_guides/model_libraries/generic/unit_models/index.html). For example, the `Mixer` unit model here must be specified the number of inlets that it will take in and the `Heater` can have specific settings enabled such as `has_pressure_change` or `has_phase_equilibrium`." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.114600Z", + "start_time": "2025-11-20T21:46:10.071845Z" + } + }, "source": [ + "m.fs.I101 = Feed(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.I102 = Feed(property_package=m.fs.thermo_params)\n", + "\n", "m.fs.M101 = Mixer(\n", " property_package=m.fs.thermo_params,\n", - " inlet_list=[\"toluene_feed\", \"hydrogen_feed\", \"vapor_recycle\"],\n", + " num_inlets=3,\n", ")\n", "\n", "m.fs.H101 = Heater(\n", @@ -304,11 +382,17 @@ " has_pressure_change=False,\n", " has_phase_equilibrium=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
            \n", "Inline Exercise:\n", @@ -325,26 +409,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.121709Z", + "start_time": "2025-11-20T21:46:10.119134Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.145853Z", + "start_time": "2025-11-20T21:46:10.127921Z" + } }, - "outputs": [], "source": [ "# Todo: Add reactor with the specifications above\n", "m.fs.R101 = StoichiometricReactor(\n", @@ -354,7 +444,9 @@ " has_heat_transfer=True,\n", " has_pressure_change=False,\n", ")" - ] + ], + "outputs": [], + "execution_count": 13 }, { "cell_type": "markdown", @@ -370,29 +462,37 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.167357Z", + "start_time": "2025-11-20T21:46:10.149935Z" + } + }, "source": [ "m.fs.F101 = Flash(\n", " property_package=m.fs.thermo_params,\n", " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us now add the Splitter(S101), PressureChanger(C101) and the second Flash(F102). " + "Let us now add the Splitter(S101) with specific names for its output (purge and recycle), PressureChanger(C101) and the second Flash(F102)." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.211911Z", + "start_time": "2025-11-20T21:46:10.173255Z" + } + }, "source": [ "m.fs.S101 = Splitter(\n", " property_package=m.fs.thermo_params,\n", @@ -412,66 +512,115 @@ " has_heat_transfer=True,\n", " has_pressure_change=True,\n", ")" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Connecting Unit Models using Arcs\n", - "\n", - "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the mixer(M101) to the inlet of the heater(H101). " + "Last, we will add the three Product blocks (P101, P102, P103). We use `Feed` blocks and `Product` blocks for convenience with reporting stream summaries and consistency" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.226989Z", + "start_time": "2025-11-20T21:46:10.216839Z" + } + }, + "source": [ + "m.fs.P101 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P102 = Product(property_package=m.fs.thermo_params)\n", + "\n", + "m.fs.P103 = Product(property_package=m.fs.thermo_params)" + ], "outputs": [], + "execution_count": 16 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + "### 2.2 Connecting Unit Models using Arcs\n", + "\n", + "We have now added all the unit models we need to the flowsheet. However, we have not yet specified how the units are to be connected. To do this, we will be using the `Arc` which is a Pyomo component that takes in two arguments: `source` and `destination`. Let us connect the outlet of the inlets (I101, I102) to the inlet of the mixer (M101) and outlet of the mixer to the inlet of the heater(H101)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "\n", - "![](HDA_flowsheet.png) \n", - "\n", + "![](HDA_flowsheet.png)" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.235541Z", + "start_time": "2025-11-20T21:46:10.231058Z" + } + }, + "source": [ + "m.fs.s01 = Arc(source=m.fs.I101.outlet, destination=m.fs.M101.inlet_1)\n", + "m.fs.s02 = Arc(source=m.fs.I102.outlet, destination=m.fs.M101.inlet_2)\n", + "m.fs.s03 = Arc(source=m.fs.M101.outlet, destination=m.fs.H101.inlet)" + ], + "outputs": [], + "execution_count": 17 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, + "source": [ "
            \n", "Inline Exercise:\n", - "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide. \n", - "
            \n", - "\n" + "Now, connect the H101 outlet to the R101 inlet using the cell above as a guide.\n", + "
            " ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.245319Z", + "start_time": "2025-11-20T21:46:10.239913Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.254153Z", + "start_time": "2025-11-20T21:46:10.248481Z" + } }, - "outputs": [], "source": [ "# Todo: Connect the H101 outlet to R101 inlet\n", "m.fs.s04 = Arc(source=m.fs.H101.outlet, destination=m.fs.R101.inlet)" - ] + ], + "outputs": [], + "execution_count": 19 }, { "cell_type": "markdown", @@ -482,17 +631,45 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.264461Z", + "start_time": "2025-11-20T21:46:10.258555Z" + } + }, "source": [ "m.fs.s05 = Arc(source=m.fs.R101.outlet, destination=m.fs.F101.inlet)\n", "m.fs.s06 = Arc(source=m.fs.F101.vap_outlet, destination=m.fs.S101.inlet)\n", + "m.fs.s07 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)\n", "m.fs.s08 = Arc(source=m.fs.S101.recycle, destination=m.fs.C101.inlet)\n", - "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.vapor_recycle)\n", - "m.fs.s10 = Arc(source=m.fs.F101.liq_outlet, destination=m.fs.F102.inlet)" + "m.fs.s09 = Arc(source=m.fs.C101.outlet, destination=m.fs.M101.inlet_3)" + ], + "outputs": [], + "execution_count": 20 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Last we will connect the outlet streams to the inlets of the Product blocks (P101, P102, P103)" ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.274505Z", + "start_time": "2025-11-20T21:46:10.268918Z" + } + }, + "source": [ + "m.fs.s10 = Arc(source=m.fs.F102.vap_outlet, destination=m.fs.P101.inlet)\n", + "m.fs.s11 = Arc(source=m.fs.F102.liq_outlet, destination=m.fs.P102.inlet)\n", + "m.fs.s12 = Arc(source=m.fs.S101.purge, destination=m.fs.P103.inlet)" + ], + "outputs": [], + "execution_count": 21 + }, { "cell_type": "markdown", "metadata": {}, @@ -502,20 +679,25 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.303264Z", + "start_time": "2025-11-20T21:46:10.278714Z" + } + }, "source": [ "TransformationFactory(\"network.expand_arcs\").apply_to(m)" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Adding expressions to compute purity and operating costs\n", + "### 2.3 Adding expressions to compute purity and operating costs\n", "\n", - "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/pyomo_modeling_components/Expressions.html\n", + "In this section, we will add a few Expressions that allows us to evaluate the performance. Expressions provide a convenient way of calculating certain values that are a function of the variables defined in the model. For more details on Expressions, please refer to: https://pyomo.readthedocs.io/en/stable/explanation/modeling/network.html.\n", "\n", "For this flowsheet, we are interested in computing the purity of the product Benzene stream (i.e. the mole fraction) and the operating cost which is a sum of the cooling and heating cost. " ] @@ -529,18 +711,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.312336Z", + "start_time": "2025-11-20T21:46:10.309074Z" + } + }, "source": [ "m.fs.purity = Expression(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", " / (\n", - " m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " + m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", + " + m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "markdown", @@ -551,14 +742,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.323538Z", + "start_time": "2025-11-20T21:46:10.318119Z" + } + }, "source": [ "m.fs.cooling_cost = Expression(\n", " expr=0.212e-7 * (-m.fs.F101.heat_duty[0]) + 0.212e-7 * (-m.fs.R101.heat_duty[0])\n", ")" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -575,14 +771,19 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.336983Z", + "start_time": "2025-11-20T21:46:10.328380Z" + } + }, "source": [ "m.fs.heating_cost = Expression(\n", " expr=2.2e-7 * m.fs.H101.heat_duty[0] + 1.9e-7 * m.fs.F102.heat_duty[0]\n", ")" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -593,64 +794,94 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.345607Z", + "start_time": "2025-11-20T21:46:10.341996Z" + } + }, "source": [ "m.fs.operating_cost = Expression(\n", " expr=(3600 * 24 * 365 * (m.fs.heating_cost + m.fs.cooling_cost))\n", ")" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing feed conditions\n", + "## 4 Specifying the Model\n", + "### 4.1 Fixing feed conditions\n", "\n", "Let us first check how many degrees of freedom exist for this flowsheet using the `degrees_of_freedom` tool we imported earlier. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.376586Z", + "start_time": "2025-11-20T21:46:10.349694Z" + } + }, "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "29\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We will now be fixing the toluene feed stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing. " + "We will now be fixing the toluene feed (`I101`) stream to the conditions shown in the flowsheet above. Please note that though this is a pure toluene feed, the remaining components are still assigned a very small non-zero value to help with convergence and initializing." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.418520Z", + "start_time": "2025-11-20T21:46:10.414167Z" + } + }, "source": [ - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(0.30)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.toluene_feed.temperature.fix(303.2)\n", - "m.fs.M101.toluene_feed.pressure.fix(350000)" - ] + "F_liq_toluene = 0.30\n", + "F_liq_non_zero = 1e-5\n", + "\n", + "F_vap_I101 = F_liq_non_zero * 4\n", + "F_liq_I101 = F_liq_toluene + F_liq_non_zero\n", + "\n", + "m.fs.I101.flow_mol_phase[0, \"Vap\"].fix(F_vap_I101)\n", + "m.fs.I101.flow_mol_phase[0, \"Liq\"].fix(F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_liq_non_zero / F_vap_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I101)\n", + "m.fs.I101.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_toluene / F_liq_I101)\n", + "m.fs.I101.temperature.fix(303.2)\n", + "m.fs.I101.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", - "Similarly, let us fix the hydrogen feed to the following conditions in the next cell:\n", + "Similarly, let us fix the hydrogen feed (`I102`) to the following conditions in the next cell:\n", "
              \n", "
            • FH2 = 0.30 mol/s
            • \n", "
            • FCH4 = 0.02 mol/s
            • \n", @@ -663,39 +894,59 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.429169Z", + "start_time": "2025-11-20T21:46:10.422052Z" + } + }, "source": [ - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"hydrogen\"].fix(0.30)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Vap\", \"methane\"].fix(0.02)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"benzene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"toluene\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"hydrogen\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.flow_mol_phase_comp[0, \"Liq\", \"methane\"].fix(1e-5)\n", - "m.fs.M101.hydrogen_feed.temperature.fix(303.2)\n", - "m.fs.M101.hydrogen_feed.pressure.fix(350000)" - ] + "F_vap_hydrogen = 0.30\n", + "F_vap_methane = 0.020\n", + "\n", + "F_vap_non_zero = 1e-5\n", + "F_liq_non_zero = F_vap_non_zero\n", + "\n", + "F_vap_I102 = F_vap_hydrogen + F_vap_methane + 2 * F_vap_non_zero\n", + "F_liq_I102 = 2 * F_vap_non_zero\n", + "\n", + "m.fs.I102.flow_mol_phase[0, \"Vap\"].fix(F_vap_I102)\n", + "m.fs.I102.flow_mol_phase[0, \"Liq\"].fix(F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"benzene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"toluene\"].fix(F_vap_non_zero / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"hydrogen\"].fix(F_vap_hydrogen / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Vap\", \"methane\"].fix(F_vap_methane / F_vap_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"benzene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "m.fs.I102.mole_frac_phase_comp[0, \"Liq\", \"toluene\"].fix(F_liq_non_zero / F_liq_I102)\n", + "\n", + "m.fs.I102.temperature.fix(303.2)\n", + "m.fs.I102.pressure.fix(350000)" + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Fixing unit model specifications\n", + "### 4.2 Fixing unit model specifications\n", "\n", "Now that we have fixed our inlet feed conditions, we will now be fixing the operating conditions for the unit models in the flowsheet. Let us set set the H101 outlet temperature to 600 K. " ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.441145Z", + "start_time": "2025-11-20T21:46:10.433569Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.fix(600)" - ] + ], + "outputs": [], + "execution_count": 31 }, { "cell_type": "markdown", @@ -706,23 +957,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.453419Z", + "start_time": "2025-11-20T21:46:10.445363Z" + } + }, "source": [ "m.fs.R101.conversion = Var(initialize=0.75, bounds=(0, 1))\n", "\n", "m.fs.R101.conv_constraint = Constraint(\n", - " expr=m.fs.R101.conversion * m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " expr=m.fs.R101.conversion\n", + " * (m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"])\n", " == (\n", - " m.fs.R101.inlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", - " - m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"toluene\"]\n", + " m.fs.R101.control_volume.properties_in[0].flow_mol_phase_comp[\"Vap\", \"toluene\"]\n", + " - m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"toluene\"\n", + " ]\n", " )\n", ")\n", "\n", "m.fs.R101.conversion.fix(0.75)\n", "m.fs.R101.heat_duty.fix(0)" - ] + ], + "outputs": [], + "execution_count": 32 }, { "cell_type": "markdown", @@ -733,17 +992,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.463025Z", + "start_time": "2025-11-20T21:46:10.457476Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature.fix(325.0)\n", "m.fs.F101.deltaP.fix(0)" - ] + ], + "outputs": [], + "execution_count": 33 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", @@ -759,30 +1027,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.472509Z", + "start_time": "2025-11-20T21:46:10.467229Z" + } }, - "outputs": [], "source": [ "# Todo: Set conditions for Flash F102" - ] + ], + "outputs": [], + "execution_count": 34 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.482109Z", + "start_time": "2025-11-20T21:46:10.475567Z" + } }, - "outputs": [], "source": [ "m.fs.F102.vap_outlet.temperature.fix(375)\n", "m.fs.F102.deltaP.fix(-200000)" - ] + ], + "outputs": [], + "execution_count": 35 }, { "cell_type": "markdown", @@ -793,17 +1069,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.491620Z", + "start_time": "2025-11-20T21:46:10.485173Z" + } + }, "source": [ "m.fs.S101.split_fraction[0, \"purge\"].fix(0.2)\n", "m.fs.C101.outlet.pressure.fix(350000)" - ] + ], + "outputs": [], + "execution_count": 36 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", @@ -815,54 +1100,83 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.503512Z", + "start_time": "2025-11-20T21:46:10.495838Z" + } }, - "outputs": [], "source": [ "# Todo: print the degrees of freedom" - ] + ], + "outputs": [], + "execution_count": 37 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.535421Z", + "start_time": "2025-11-20T21:46:10.507798Z" + } }, - "outputs": [], "source": [ "print(degrees_of_freedom(m))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "execution_count": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Initialization\n", + "## 5 Initializing the Model\n", + "\n", + "\n", + "\n", + "When a flowsheet contains a recycle loop, the outlet of a downstream unit becomes the inlet of an upstream unit, creating a cyclic dependency that prevents straightforward calculation of all stream conditions. The tear‐stream method is necessary because it “breaks” this loop: you select one recycle stream as the tear, assign it an initial guess, and then solve the rest of the flowsheet as if it were acyclic. Once the downstream units compute their outputs, you compare the calculated value of the torn stream to your initial guess and iteratively adjust until they coincide. Without tearing, the solver cannot establish a proper topological sequence or drive the recycle to convergence, making initialization—and ultimately steady‐state convergence—impossible.\n", "\n", + "It is important to determine the tear stream for a flowsheet which will be demonstrated below.\n", "\n", - "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet.\n", "\n", - "![](HDA_flowsheet.png) \n" + "![](HDA_flowsheet.png)\n", + "\n", + "Currently, there are two methods of initializing a full flowsheet: using the sequential decomposition tool, or manually propagating through the flowsheet. Both methods will be shown.\n", + "\n", + "### 5.1 Sequential Decomposition\n", + "\n", + "This section will demonstrate how to use the built-in sequential decomposition tool to initialize our flowsheet. Sequential Decomposition is a tool from Pyomo where the documentation can be found here https://Pyomo.readthedocs.io/en/stable/explanation/modeling/network.html#sequential-decomposition\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Let us first create an object for the SequentialDecomposition and specify our options for this. " + "Let us first create an object for the SequentialDecomposition and specify our options for this. We can also create a graph for our flowsheet to determine the tear set and order." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.578789Z", + "start_time": "2025-11-20T21:46:10.574025Z" + } + }, "source": [ "seq = SequentialDecomposition()\n", "seq.options.select_tear_method = \"heuristic\"\n", @@ -873,7 +1187,9 @@ "G = seq.create_graph(m)\n", "heuristic_tear_set = seq.tear_set_arcs(G, method=\"heuristic\")\n", "order = seq.calculation_order(G)" - ] + ], + "outputs": [], + "execution_count": 40 }, { "cell_type": "markdown", @@ -884,13 +1200,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.588985Z", + "start_time": "2025-11-20T21:46:10.581810Z" + } + }, "source": [ "for o in heuristic_tear_set:\n", " print(o.name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.s03\n" + ] + } + ], + "execution_count": 41 }, { "cell_type": "markdown", @@ -901,15 +1230,32 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { - "scrolled": true + "scrolled": true, + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.602315Z", + "start_time": "2025-11-20T21:46:10.599259Z" + } }, - "outputs": [], "source": [ "for o in order:\n", " print(o[0].name)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "fs.I101\n", + "fs.R101\n", + "fs.F101\n", + "fs.S101\n", + "fs.C101\n", + "fs.M101\n" + ] + } + ], + "execution_count": 42 }, { "cell_type": "markdown", @@ -920,25 +1266,30 @@ "![](HDA_tear_stream.png) \n", "\n", "\n", - "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. We will need to provide a reasonable guess for this." + "The SequentialDecomposition tool has determined that the tear stream is the mixer outlet. You can see this shown in the picture of the flowsheet above as the outlet of the mixer as the two lines crossing it identifying it as the tear stream. We will need to provide a reasonable guess for this." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.620357Z", + "start_time": "2025-11-20T21:46:10.617116Z" + } + }, "source": [ "tear_guesses = {\n", - " \"flow_mol_phase_comp\": {\n", - " (0, \"Vap\", \"benzene\"): 1e-5,\n", - " (0, \"Vap\", \"toluene\"): 1e-5,\n", - " (0, \"Vap\", \"hydrogen\"): 0.30,\n", - " (0, \"Vap\", \"methane\"): 0.02,\n", - " (0, \"Liq\", \"benzene\"): 1e-5,\n", - " (0, \"Liq\", \"toluene\"): 0.30,\n", - " (0, \"Liq\", \"hydrogen\"): 1e-5,\n", - " (0, \"Liq\", \"methane\"): 1e-5,\n", + " \"flow_mol_phase\": {\n", + " (0, \"Liq\"): F_liq_I101,\n", + " (0, \"Vap\"): F_vap_I102,\n", + " },\n", + " \"mole_frac_phase_comp\": {\n", + " (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + " (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + " (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + " (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + " (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", " },\n", " \"temperature\": {0: 303},\n", " \"pressure\": {0: 350000},\n", @@ -946,7 +1297,9 @@ "\n", "# Pass the tear_guess to the SD tool\n", "seq.set_guesses_for(m.fs.H101.inlet, tear_guesses)" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "markdown", @@ -957,9 +1310,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:10.638254Z", + "start_time": "2025-11-20T21:46:10.635136Z" + } + }, "source": [ "def function(unit):\n", " try:\n", @@ -968,7 +1324,9 @@ " except InitializationError:\n", " solver = get_solver()\n", " solver.solve(unit)" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "markdown", @@ -979,118 +1337,1232 @@ }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.022425Z", + "start_time": "2025-11-20T21:46:10.648251Z" + } + }, + "source": "seq.run(m, function)", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:10 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:11 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.I102.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:12 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:13 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:14 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.H101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.R101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:15 [INFO] idaes.init.fs.F101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.purge_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101.recycle_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.S101: Initialization Step 2 Complete: optimal - \n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.C101.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_1_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_2_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.inlet_3_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101.mixed_state: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.M101: Initialization Complete: optimal - \n", + "WARNING: Wegstein failed to converge in 3 iterations\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P103.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_in: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.F102.control_volume.properties_out: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Starting initialization routine\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: State variable initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P101.properties: Property initialization routine finished.\n", + "2025-11-20 14:46:16 [INFO] idaes.init.fs.P102.properties: Starting initialization routine\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Bubble, dew, and critical point initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Equilibrium temperature initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: State variable initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Phase equilibrium initialization completed.\n", + "2025-11-20 14:46:17 [INFO] idaes.init.fs.P102.properties: Property initialization routine finished.\n" + ] + } + ], + "execution_count": 45 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Manual Propagation Method\n", + "\n", + "This method uses a more direct approach to initialize the flowsheet, utilizing the updated initializer method and propagating manually through the flowsheet and solving for the tear stream directly.\n", + "Lets first import a helper function that will help us manually propagate and step through the flowsheet" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.069766Z", + "start_time": "2025-11-20T21:46:17.066725Z" + } + }, + "source": [ + "from idaes.core.util.initialization import propagate_state" + ], + "outputs": [], + "execution_count": 46 + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "Now we can setup our initial guesses for the tear stream which we know is the outlet of the `Mixer` or the inlet of the `Heater`. We can use the same initial guesses used in the first method. We also want to ensure that the degrees of freedom are consistent while we manually initialize the model.\n", + "\n", + "We will first ensure that are current degrees of freedom is still zero" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.080343Z", + "start_time": "2025-11-20T21:46:17.077382Z" + } + }, + "source": "# print(f\"The DOF is {degrees_of_freedom(m)} initially\")", "outputs": [], + "execution_count": 47 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "seq.run(m, function)" + "Now we can manually deactivate the tear stream, creating a separation between the `Mixer` and `Heater`. This should reduce the degrees of freedom by 10 since the inlet of the `Heater` now contains no values to solve the unit model. To deactivate a stream, simply use `m.fs.s03_expanded.deactivate()`. This expanded stream is just a different version of the `Arc` stream that is able to be deactivated." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.093180Z", + "start_time": "2025-11-20T21:46:17.089671Z" + } + }, + "source": [ + "# m.fs.s03_expanded.deactivate()\n", + "#\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after deactivating the tear stream\")" + ], + "outputs": [], + "execution_count": 48 + }, { "cell_type": "markdown", "metadata": {}, + "source": [ + "Now we can provide the `Heater` inlet 10 guess values to bring the degrees of freedom back to 0 and start the manual initialization process. We can run this convenient loop to assign each of these guesses to the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.105510Z", + "start_time": "2025-11-20T21:46:17.099824Z" + } + }, + "source": [ + "# tear_guesses = {\n", + "# \"flow_mol_phase\": {\n", + "# (0, \"Liq\"): F_liq_I101,\n", + "# (0, \"Vap\"): F_vap_I102,\n", + "#\n", + "# },\n", + "# \"mole_frac_phase_comp\": {\n", + "# (0, \"Liq\", \"benzene\"): 1e-5 / F_liq_I101,\n", + "# (0, \"Liq\", \"toluene\"): 0.30 / F_liq_I101,\n", + "# (0, \"Vap\", \"benzene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"toluene\"): 1e-5 / F_vap_I102,\n", + "# (0, \"Vap\", \"methane\"): 0.02 / F_vap_I102,\n", + "# (0, \"Vap\", \"hydrogen\"): 0.30 / F_vap_I102,\n", + "# },\n", + "# \"temperature\": {0: 303},\n", + "# \"pressure\": {0: 350000},\n", + "# }\n", + "#\n", + "# for k, v in tear_guesses.items():\n", + "# for k1, v1 in v.items():\n", + "# getattr(m.fs.s03.destination, k)[k1].fix(v1)\n", + "#\n", + "# DOF_initial = degrees_of_freedom(m)\n", + "# print(f\"The DOF is {degrees_of_freedom(m)} after providing the initial guesses\")" + ], + "outputs": [], + "execution_count": 49 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next step is to manually initialize each unit model starting from the `Heater` and then propagate the connection between it and the next unit model. This manual process ensures a strict order to the user's specification if that is desired. The current standard for initializing a unit model is to use an initializer object most compatible for that unit model. This can most often be done by utilizing the `default_initializer()` method attached to the unit model and then to call the `initialize()` method with the unit model as the argument." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.117110Z", + "start_time": "2025-11-20T21:46:17.113630Z" + } + }, + "source": [ + "# m.fs.H101.default_initializer().initialize(m.fs.H101) # Initialize Heater\n", + "# propagate_state(m.fs.s04) # Establish connection between Heater and Reactor\n", + "#\n", + "# m.fs.R101.default_initializer().initialize(m.fs.R101) # Initialize Reactor\n", + "# propagate_state(m.fs.s05) # Establish connection between Reactor and First Flash Unit\n", + "#\n", + "# m.fs.F101.default_initializer().initialize(m.fs.F101) # Initialize First Flash Unit\n", + "# propagate_state(m.fs.s06) # Establish connection between First Flash Unit and Splitter\n", + "# propagate_state(m.fs.s07) # Establish connection between First Flash Unit and Second Flash Unit\n", + "#\n", + "# m.fs.S101.default_initializer().initialize(m.fs.S101) # Initialize Splitter\n", + "# propagate_state(m.fs.s08) # Establish connection between Splitter and Compressor\n", + "#\n", + "# m.fs.C101.default_initializer().initialize(m.fs.C101) # Initialize Compressor\n", + "# propagate_state(m.fs.s09) # Establish connection between Compressor and Mixer\n", + "#\n", + "# m.fs.I101.default_initializer().initialize(m.fs.I101) # Initialize Toluene Inlet\n", + "# propagate_state(m.fs.s01) # Establish connection between Toluene Inlet and Mixer\n", + "#\n", + "# m.fs.I102.default_initializer().initialize(m.fs.I102) # Initialize Hydrogen Inlet\n", + "# propagate_state(m.fs.s02) # Establish connection between Hydrogen Inlet and Mixer\n", + "#\n", + "# m.fs.M101.default_initializer().initialize(m.fs.M101) # Initialize Mixer\n", + "# propagate_state(m.fs.s03) # Establish connection between Mixer and Heater\n", + "#\n", + "# m.fs.F102.default_initializer().initialize(m.fs.F102) # Initialize Second Flash Unit\n", + "# propagate_state(m.fs.s10) # Establish connection between Second Flash Unit and Benzene Product\n", + "# propagate_state(m.fs.s11) # Establish connection between Second Flash Unit and Toluene Product\n", + "# propagate_state(m.fs.s12) # Establish connection between Splitter and Purge Product" + ], + "outputs": [], + "execution_count": 50 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we solve the system to allow the outlet of the mixer to reach a converged congruence with the inlet of the heater." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.226222Z", + "start_time": "2025-11-20T21:46:17.129942Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 300,\n", + " \"tol\": 1e-8,\n", + "}\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", + "results = solver.solve(m, tee=True)" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=300\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpvgsmpj67\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 3.35e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.07e+03 1.08e+01 -1.0 1.21e+03 - 8.49e-01 6.80e-01h 1\n", + " 2 0.0000000e+00 1.66e+02 4.55e+02 -1.0 7.65e+02 - 9.90e-01 8.44e-01h 1\n", + " 3 0.0000000e+00 5.53e+00 2.00e+02 -1.0 1.30e+02 - 9.90e-01 9.67e-01h 1\n", + " 4 0.0000000e+00 5.22e-02 8.91e+03 -1.0 4.05e+00 - 1.00e+00 9.91e-01h 1\n", + " 5 0.0000000e+00 1.46e-04 1.02e+04 -1.0 3.80e-02 - 1.00e+00 9.97e-01h 1\n", + " 6 0.0000000e+00 9.46e-11 6.27e-01 -1.0 1.06e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 6\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 9.4587448984384537e-11 9.4587448984384537e-11\n", + "\n", + "\n", + "Number of objective function evaluations = 7\n", + "Number of objective gradient evaluations = 7\n", + "Number of equality constraint evaluations = 7\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 7\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 6\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.009\n", + "Total CPU secs in NLP function evaluations = 0.001\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 51 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that the flowsheet is initialized, we can unfix the guesses for the `Heater` and reactive the tear stream to complete the final solve." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.258332Z", + "start_time": "2025-11-20T21:46:17.233298Z" + } + }, + "source": [ + "for k, v in tear_guesses.items():\n", + " for k1, v1 in v.items():\n", + " getattr(m.fs.H101.inlet, k)[k1].unfix()\n", + "\n", + "m.fs.s03_expanded.activate()\n", + "print(\n", + " f\"The DOF is {degrees_of_freedom(m)} after unfixing the values and reactivating the tear stream\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The DOF is 0 after unfixing the values and reactivating the tear stream\n" + ] + } + ], + "execution_count": 52 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6 Solving the Model" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [] + }, + "source": [ + "We have now initialized the flowsheet. Lets set up some solving options before simulating the flowsheet. We want to specify the scaling method, number of iterations, and tolerance. More specific or advanced options can be found at the documentation for IPOPT https://coin-or.github.io/Ipopt/OPTIONS.html" + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.268422Z", + "start_time": "2025-11-20T21:46:17.265316Z" + } + }, + "source": [ + "optarg = {\n", + " \"nlp_scaling_method\": \"user-scaling\",\n", + " \"OF_ma57_automatic_scaling\": \"yes\",\n", + " \"max_iter\": 1000,\n", + " \"tol\": 1e-8,\n", + "}" + ], + "outputs": [], + "execution_count": 53 + }, + { + "cell_type": "markdown", + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", - "We have now initialized the flowsheet. Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", - " \n", + "Let us run the flowsheet in a simulation mode to look at the results. To do this, complete the last line of code where we pass the model to the solver. You will need to type the following:\n", + "\n", + "solver = get_solver(solver_options=optarg)
              \n", "results = solver.solve(m, tee=True)\n", "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
              \n", - "\n" + "Use Shift+Enter to run the cell once you have typed in your code.\n", + "
              \n" ] }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.285774Z", + "start_time": "2025-11-20T21:46:17.281657Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", "\n", - "\n", "# Solve the model" - ] + ], + "outputs": [], + "execution_count": 54 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.382669Z", + "start_time": "2025-11-20T21:46:17.293013Z" + } }, - "outputs": [], "source": [ "# Create the solver object\n", - "from idaes.core.solvers import get_solver\n", - "\n", - "solver = get_solver()\n", + "solver = get_solver(\"ipopt_v2\", options=optarg)\n", "\n", "# Solve the model\n", "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpi86o_z2t\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 920\n", + "Number of nonzeros in inequality constraint Jacobian.: 0\n", + "Number of nonzeros in Lagrangian Hessian.............: 456\n", + "\n", + "Total number of variables............................: 218\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 147\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 218\n", + "Total number of inequality constraints...............: 0\n", + " inequality constraints with only lower bounds: 0\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 0\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 0.0000000e+00 1.64e+03 1.00e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (10193)\n", + " 1 0.0000000e+00 1.84e+01 4.18e+00 -1.0 4.14e-01 - 9.90e-01 9.89e-01h 1\n", + " 2 0.0000000e+00 1.82e-01 3.87e+00 -1.0 3.76e-01 - 9.90e-01 9.90e-01h 1\n", + " 3 0.0000000e+00 6.96e-04 4.53e+02 -1.0 3.70e-02 - 9.92e-01 9.96e-01h 1\n", + " 4 0.0000000e+00 4.52e-09 8.75e-01 -1.0 3.82e-04 - 1.00e+00 1.00e+00h 1\n", + "\n", + "Number of Iterations....: 4\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Dual infeasibility......: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Constraint violation....: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "Complementarity.........: 0.0000000000000000e+00 0.0000000000000000e+00\n", + "Overall NLP error.......: 4.5247361413203180e-09 4.5247361413203180e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 5\n", + "Number of objective gradient evaluations = 5\n", + "Number of equality constraint evaluations = 5\n", + "Number of inequality constraint evaluations = 0\n", + "Number of equality constraint Jacobian evaluations = 5\n", + "Number of inequality constraint Jacobian evaluations = 0\n", + "Number of Lagrangian Hessian evaluations = 4\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.008\n", + "Total CPU secs in NLP function evaluations = 0.000\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 55 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Analyze the results of the square problem\n", - "\n", + "## 7 Analyze the results\n", "\n", - "What is the total operating cost? " + "\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, + "source": [ + "If the IDAES UI package was installed with the `idaes-pse` installation or installed separately, you can run the flowsheet visualizer to see a full diagram of the full process that is generated and displayed on a browser window.\n" + ] + }, + { + "cell_type": "code", + "metadata": { + "tags": [ + "noauto" + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.403453Z", + "start_time": "2025-11-20T21:46:17.400372Z" + } + }, + "source": [ + "# m.fs.visualize(\"HDA-Flowsheet\")" + ], "outputs": [], + "execution_count": 57 + }, + { + "cell_type": "markdown", + "metadata": {}, "source": [ - "print(\"operating cost = $\", value(m.fs.operating_cost))" + "Otherwise, we can run the `m.fs.report()` method to see a full summary of the solved flowsheet. It is recommended to adjust the width of the output as much as possible for the cleanest display." ] }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.448969Z", + "start_time": "2025-11-20T21:46:17.421434Z" + } + }, + "source": [ + "m.fs.report()" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Flowsheet : fs Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units s01 s02 s03 s04 s05 s06 s07 s08 s09 s10 s11 s12 \n", + " Total Molar Flowrate mole / second 0.30005 0.32004 2.0320 2.0320 2.0320 1.7648 0.26712 1.4119 1.4119 0.17224 0.094878 0.35297\n", + " Total Mole Fraction benzene dimensionless 6.6656e-05 6.2492e-05 0.058732 0.058732 0.17408 0.084499 0.76595 0.084499 0.084499 0.82430 0.66001 0.084499\n", + " Total Mole Fraction toluene dimensionless 0.99987 6.2492e-05 0.15380 0.15380 0.038450 0.0088437 0.23405 0.0088437 0.0088437 0.17570 0.33999 0.0088437\n", + " Total Mole Fraction hydrogen dimensionless 3.3328e-05 0.93738 0.27683 0.27683 0.16148 0.18592 6.9600e-09 0.18592 0.18592 1.0794e-08 1.1376e-15 0.18592\n", + " Total Mole Fraction methane dimensionless 3.3328e-05 0.062492 0.51064 0.51064 0.62599 0.72074 2.6982e-08 0.72074 0.72074 4.1844e-08 4.4103e-15 0.72074\n", + " Temperature kelvin 303.20 303.20 324.54 600.00 822.07 325.00 325.00 325.00 325.00 375.00 375.00 325.00\n", + " Pressure pascal 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 3.5000e+05 1.5000e+05 1.5000e+05 3.5000e+05\n", + "====================================================================================\n" + ] + } + ], + "execution_count": 58 + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? " + "What is the total operating cost?" ] }, { "cell_type": "code", - "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.475550Z", + "start_time": "2025-11-20T21:46:17.472001Z" + } + }, + "source": [ + "print(\"operating cost = $\", value(m.fs.operating_cost))" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 424513.9640158265\n" + ] + } + ], + "execution_count": 59 + }, + { + "cell_type": "markdown", "metadata": {}, - "outputs": [], + "source": [ + "For this operating cost, what is the amount of benzene we are able to produce and what purity we are able to achieve? We can look at a specific unit models stream table with the same `report()` method." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.596910Z", + "start_time": "2025-11-20T21:46:17.580529Z" + } + }, "source": [ "m.fs.F102.report()\n", "\n", "print()\n", "print(\"benzene purity = \", value(m.fs.purity))" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 7346.0 : watt : False : (None, None)\n", + " Pressure Change : -2.0000e+05 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.26712 - - \n", + " Total Mole Fraction benzene dimensionless 0.76595 - - \n", + " Total Mole Fraction toluene dimensionless 0.23405 - - \n", + " Total Mole Fraction hydrogen dimensionless 6.9600e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.6982e-08 - - \n", + " Temperature kelvin 325.00 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.094878 \n", + " flow_mol_phase Vap mole / second - 0.17224 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.66001 0.66001 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.33999 0.33999 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.82430 0.82430 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.17570 0.17570 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.0794e-08 1.0794e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.1844e-08 4.1844e-08 \n", + " temperature kelvin - 375.00 375.00 \n", + " pressure pascal - 1.5000e+05 1.5000e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8242963521555956\n" + ] + } + ], + "execution_count": 61 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101.\n", - "\n", - "
              \n", - "Inline Exercise:\n", - "How much benzene are we losing in the F101 vapor outlet stream?\n", - "
              \n" + "Next, let's look at how much benzene we are losing with the light gases out of F101. IDAES has tools for creating stream tables based on the `Arcs` and/or `Ports` in a flowsheet. Let us create and print a simple stream table showing the stream leaving the reactor and the vapor stream from F101." ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.648524Z", + "start_time": "2025-11-20T21:46:17.638446Z" + } + }, "source": [ "from idaes.core.util.tables import (\n", " create_stream_table_dataframe,\n", @@ -1099,25 +2571,30 @@ "\n", "st = create_stream_table_dataframe({\"Reactor\": m.fs.s05, \"Light Gases\": m.fs.s06})\n", "print(stream_table_dataframe_to_string(st))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "
              \n", - "Inline Exercise:\n", - "You can query additional variables here if you like. \n", - "\n", - "Use Shift+Enter to run the cell once you have typed in your code. \n", - "
              \n" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Units Reactor Light Gases\n", + "Total Molar Flowrate mole / second 2.0320 1.7648 \n", + "Total Mole Fraction benzene dimensionless 0.17408 0.084499 \n", + "Total Mole Fraction toluene dimensionless 0.038450 0.0088437 \n", + "Total Mole Fraction hydrogen dimensionless 0.16148 0.18592 \n", + "Total Mole Fraction methane dimensionless 0.62599 0.72074 \n", + "Temperature kelvin 822.07 325.00 \n", + "Pressure pascal 3.5000e+05 3.5000e+05 \n" + ] + } + ], + "execution_count": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization\n", + "## 8 Optimization\n", "\n", "\n", "We saw from the results above that the total operating cost for the base case was $419,122 per year. We are producing 0.142 mol/s of benzene at a purity of 82\\%. However, we are losing around 42\\% of benzene in F101 vapor outlet stream. \n", @@ -1144,12 +2621,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.675626Z", + "start_time": "2025-11-20T21:46:17.671136Z" + } + }, "source": [ "m.fs.objective = Objective(expr=m.fs.operating_cost)" - ] + ], + "outputs": [], + "execution_count": 64 }, { "cell_type": "markdown", @@ -1160,19 +2642,28 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.691883Z", + "start_time": "2025-11-20T21:46:17.687385Z" + } + }, "source": [ "m.fs.H101.outlet.temperature.unfix()\n", "m.fs.R101.heat_duty.unfix()\n", "m.fs.F101.vap_outlet.temperature.unfix()\n", "m.fs.F102.vap_outlet.temperature.unfix()" - ] + ], + "outputs": [], + "execution_count": 65 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", @@ -1185,30 +2676,38 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.707409Z", + "start_time": "2025-11-20T21:46:17.704141Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102" - ] + ], + "outputs": [], + "execution_count": 66 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.720592Z", + "start_time": "2025-11-20T21:46:17.717532Z" + } }, - "outputs": [], "source": [ "# Todo: Unfix deltaP for F102\n", "m.fs.F102.deltaP.unfix()" - ] + ], + "outputs": [], + "execution_count": 67 }, { "cell_type": "markdown", @@ -1227,17 +2726,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.779305Z", + "start_time": "2025-11-20T21:46:17.775669Z" + } + }, "source": [ "m.fs.H101.outlet.temperature[0].setlb(500)\n", "m.fs.H101.outlet.temperature[0].setub(600)" - ] + ], + "outputs": [], + "execution_count": 69 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", @@ -1249,31 +2757,39 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.797044Z", + "start_time": "2025-11-20T21:46:17.794614Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature" - ] + ], + "outputs": [], + "execution_count": 70 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.812504Z", + "start_time": "2025-11-20T21:46:17.807564Z" + } }, - "outputs": [], "source": [ "# Todo: Set the bounds for reactor outlet temperature\n", "m.fs.R101.outlet.temperature[0].setlb(600)\n", "m.fs.R101.outlet.temperature[0].setub(800)" - ] + ], + "outputs": [], + "execution_count": 71 }, { "cell_type": "markdown", @@ -1284,9 +2800,12 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.827227Z", + "start_time": "2025-11-20T21:46:17.822681Z" + } + }, "source": [ "m.fs.F101.vap_outlet.temperature[0].setlb(298.0)\n", "m.fs.F101.vap_outlet.temperature[0].setub(450.0)\n", @@ -1294,7 +2813,9 @@ "m.fs.F102.vap_outlet.temperature[0].setub(450.0)\n", "m.fs.F102.vap_outlet.pressure[0].setlb(105000)\n", "m.fs.F102.vap_outlet.pressure[0].setub(110000)" - ] + ], + "outputs": [], + "execution_count": 72 }, { "cell_type": "markdown", @@ -1305,19 +2826,31 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.848212Z", + "start_time": "2025-11-20T21:46:17.844101Z" + } + }, "source": [ "m.fs.overhead_loss = Constraint(\n", - " expr=m.fs.F101.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", - " <= 0.20 * m.fs.R101.outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"]\n", + " expr=m.fs.F101.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " <= 0.20\n", + " * m.fs.R101.control_volume.properties_out[0].flow_mol_phase_comp[\"Vap\", \"benzene\"]\n", ")" - ] + ], + "outputs": [], + "execution_count": 73 }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "tags": [ + "exercise" + ] + }, "source": [ "
              \n", "Inline Exercise:\n", @@ -1329,32 +2862,43 @@ }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "exercise" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.862411Z", + "start_time": "2025-11-20T21:46:17.859385Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint" - ] + ], + "outputs": [], + "execution_count": 74 }, { "cell_type": "code", - "execution_count": null, "metadata": { "tags": [ "solution" - ] + ], + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.876414Z", + "start_time": "2025-11-20T21:46:17.872250Z" + } }, - "outputs": [], "source": [ "# Todo: Add minimum product flow constraint\n", "m.fs.product_flow = Constraint(\n", - " expr=m.fs.F102.vap_outlet.flow_mol_phase_comp[0, \"Vap\", \"benzene\"] >= 0.15\n", + " expr=m.fs.F102.control_volume.properties_out[0].flow_mol_phase_comp[\n", + " \"Vap\", \"benzene\"\n", + " ]\n", + " >= 0.15\n", ")" - ] + ], + "outputs": [], + "execution_count": 75 }, { "cell_type": "markdown", @@ -1365,12 +2909,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:17.890250Z", + "start_time": "2025-11-20T21:46:17.887141Z" + } + }, "source": [ "m.fs.product_purity = Constraint(expr=m.fs.purity >= 0.80)" - ] + ], + "outputs": [], + "execution_count": 76 }, { "cell_type": "markdown", @@ -1384,27 +2933,141 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.024828Z", + "start_time": "2025-11-20T21:46:17.897344Z" + } + }, "source": [ "results = solver.solve(m, tee=True)" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ipopt 3.13.2: linear_solver=\"ma57\"\n", + "max_iter=1000\n", + "nlp_scaling_method=\"user-scaling\"\n", + "tol=1e-08\n", + "option_file_name=\"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\"\n", + "\n", + "Using option file \"C:\\Users\\Tanner\\AppData\\Local\\Temp\\tmpqgb86kxz\\unknown.36084.37884.opt\".\n", + "\n", + "\n", + "******************************************************************************\n", + "This program contains Ipopt, a library for large-scale nonlinear optimization.\n", + " Ipopt is released as open source code under the Eclipse Public License (EPL).\n", + " For more information visit http://projects.coin-or.org/Ipopt\n", + "\n", + "This version of Ipopt was compiled from source code available at\n", + " https://github.com/IDAES/Ipopt as part of the Institute for the Design of\n", + " Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE\n", + " Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.\n", + "\n", + "This version of Ipopt was compiled using HSL, a collection of Fortran codes\n", + " for large-scale scientific computation. All technical papers, sales and\n", + " publicity material resulting from use of the HSL codes within IPOPT must\n", + " contain the following acknowledgement:\n", + " HSL, a collection of Fortran codes for large-scale scientific\n", + " computation. See http://www.hsl.rl.ac.uk.\n", + "******************************************************************************\n", + "\n", + "This is Ipopt version 3.13.2, running with linear solver ma57.\n", + "\n", + "Number of nonzeros in equality constraint Jacobian...: 938\n", + "Number of nonzeros in inequality constraint Jacobian.: 9\n", + "Number of nonzeros in Lagrangian Hessian.............: 504\n", + "\n", + "Reallocating memory for MA57: lfact (10594)\n", + "Total number of variables............................: 224\n", + " variables with only lower bounds: 56\n", + " variables with lower and upper bounds: 151\n", + " variables with only upper bounds: 0\n", + "Total number of equality constraints.................: 219\n", + "Total number of inequality constraints...............: 3\n", + " inequality constraints with only lower bounds: 2\n", + " inequality constraints with lower and upper bounds: 0\n", + " inequality constraints with only upper bounds: 1\n", + "\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 0 4.2451396e+05 4.00e+04 6.94e+00 -1.0 0.00e+00 - 0.00e+00 0.00e+00 0\n", + "Reallocating memory for MA57: lfact (11249)\n", + " 1 4.2182392e+05 4.00e+04 6.94e+00 -1.0 3.47e+07 - 3.71e-05 1.25e-05f 1\n", + " 2 4.2170773e+05 4.00e+04 8.41e+01 -1.0 1.49e+06 - 3.32e-04 1.53e-05f 1\n", + " 3 4.1795462e+05 4.00e+04 6.82e+01 -1.0 1.43e+06 - 4.98e-04 5.60e-04f 1\n", + " 4 3.0650178e+05 4.00e+04 3.09e+02 -1.0 1.26e+07 - 2.61e-05 1.17e-03f 1\n", + " 5 3.0553183e+05 3.99e+04 3.25e+04 -1.0 1.48e+05 - 1.28e-01 1.02e-03f 1\n", + " 6 3.0565526e+05 3.91e+04 5.25e+04 -1.0 3.99e+04 - 1.13e-01 2.09e-02h 2\n", + " 7 3.0601574e+05 3.59e+04 4.21e+04 -1.0 3.91e+04 - 5.17e-02 8.21e-02h 2\n", + " 8 3.0674242e+05 2.95e+04 8.41e+04 -1.0 3.59e+04 - 4.38e-01 1.79e-01h 1\n", + " 9 3.1153051e+05 1.11e+04 5.73e+04 -1.0 2.95e+04 - 8.56e-01 6.23e-01h 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 10 3.1154545e+05 1.09e+04 5.69e+04 -1.0 1.19e+04 - 6.57e-02 2.37e-02h 1\n", + " 11 3.1159568e+05 1.08e+04 5.66e+04 -1.0 1.68e+04 - 2.23e-02 8.97e-03h 1\n", + " 12 3.1610911e+05 2.56e+03 2.13e+05 -1.0 1.68e+04 - 9.47e-01 7.94e-01h 1\n", + " 13 3.1708718e+05 1.16e+03 9.56e+04 -1.0 4.45e+03 - 9.90e-01 5.53e-01h 1\n", + " 14 3.1796760e+05 4.06e+02 1.14e+03 -1.0 1.27e+04 - 9.95e-01 9.87e-01h 1\n", + " 15 3.1802429e+05 5.35e+00 6.53e+02 -1.0 8.29e+01 - 1.00e+00 9.89e-01h 1\n", + " 16 3.1802524e+05 1.77e-04 5.89e+02 -1.0 5.10e-01 - 1.00e+00 1.00e+00h 1\n", + " 17 3.1802492e+05 5.34e-06 1.83e+06 -2.5 1.32e+00 - 3.33e-01 1.00e+00f 1\n", + " 18 3.1802492e+05 1.70e-09 9.74e-03 -2.5 2.42e-02 - 1.00e+00 1.00e+00h 1\n", + " 19 3.1802491e+05 4.41e-09 1.03e-01 -5.7 3.83e-02 - 1.00e+00 1.00e+00f 1\n", + "iter objective inf_pr inf_du lg(mu) ||d|| lg(rg) alpha_du alpha_pr ls\n", + " 20 3.1802491e+05 2.39e-03 8.22e-09 -5.7 2.88e+01 - 1.00e+00 1.00e+00h 1\n", + " 21 3.1802491e+05 8.00e-11 9.72e-09 -5.7 4.08e-04 - 1.00e+00 1.00e+00h 1\n", + " 22 3.1802491e+05 2.47e-03 1.19e-01 -8.6 2.93e+01 - 9.99e-01 1.00e+00h 1\n", + " 23 3.1802491e+05 2.41e+02 2.13e-09 -8.6 9.27e+03 - 1.00e+00 1.00e+00h 1\n", + " 24 3.1802491e+05 6.96e-03 3.66e-09 -8.6 1.88e+02 - 1.00e+00 1.00e+00h 1\n", + " 25 3.1802491e+05 3.61e-06 1.59e-09 -8.6 1.21e+00 - 1.00e+00 1.00e+00h 1\n", + " 26 3.1802491e+05 2.29e-05 4.82e-09 -8.6 3.07e+00 - 1.00e+00 1.00e+00h 1\n", + " 27 3.1802491e+05 9.42e-07 5.47e-09 -8.6 6.24e-01 - 1.00e+00 1.00e+00h 1\n", + " 28 3.1802491e+05 1.16e-10 9.67e-09 -8.6 3.01e+00 - 1.00e+00 1.00e+00H 1\n", + "\n", + "Number of Iterations....: 28\n", + "\n", + " (scaled) (unscaled)\n", + "Objective...............: 3.1802490940142004e+05 3.1802490940142004e+05\n", + "Dual infeasibility......: 9.6706583658121551e-09 9.6706583658121551e-09\n", + "Constraint violation....: 1.1641532182693481e-10 1.1641532182693481e-10\n", + "Complementarity.........: 2.5059899579272651e-09 2.5059899579272651e-09\n", + "Overall NLP error.......: 2.2246107350021195e-10 9.6706583658121551e-09\n", + "\n", + "\n", + "Number of objective function evaluations = 35\n", + "Number of objective gradient evaluations = 29\n", + "Number of equality constraint evaluations = 35\n", + "Number of inequality constraint evaluations = 35\n", + "Number of equality constraint Jacobian evaluations = 29\n", + "Number of inequality constraint Jacobian evaluations = 29\n", + "Number of Lagrangian Hessian evaluations = 28\n", + "Total CPU secs in IPOPT (w/o function evaluations) = 0.036\n", + "Total CPU secs in NLP function evaluations = 0.006\n", + "\n", + "EXIT: Optimal Solution Found.\n" + ] + } + ], + "execution_count": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Optimization Results\n", + "### 8.1 Optimization Results\n", "\n", "Display the results and product specifications" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.074231Z", + "start_time": "2025-11-20T21:46:18.053675Z" + } + }, "source": [ "print(\"operating cost = $\", value(m.fs.operating_cost))\n", "\n", @@ -1419,7 +3082,89 @@ "print()\n", "print(\"Overhead loss in F101\")\n", "m.fs.F101.report()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "operating cost = $ 318024.90940142004\n", + "\n", + "Product flow rate and purity in F102\n", + "\n", + "====================================================================================\n", + "Unit : fs.F102 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : 8369.3 : watt : False : (None, None)\n", + " Pressure Change : -2.4500e+05 : pascal : False : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 0.28812 - - \n", + " Total Mole Fraction benzene dimensionless 0.75463 - - \n", + " Total Mole Fraction toluene dimensionless 0.24537 - - \n", + " Total Mole Fraction hydrogen dimensionless 7.5018e-09 - - \n", + " Total Mole Fraction methane dimensionless 2.5957e-08 - - \n", + " Temperature kelvin 301.88 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.10493 \n", + " flow_mol_phase Vap mole / second - 0.18319 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.64256 0.64256 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.35744 0.35744 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.81883 0.81883 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.18117 0.18117 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 1.1799e-08 1.1799e-08 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 4.0825e-08 4.0825e-08 \n", + " temperature kelvin - 362.93 362.93 \n", + " pressure pascal - 1.0500e+05 1.0500e+05 \n", + "====================================================================================\n", + "\n", + "benzene purity = 0.8188295888411846\n", + "\n", + "Overhead loss in F101\n", + "\n", + "====================================================================================\n", + "Unit : fs.F101 Time: 0.0\n", + "------------------------------------------------------------------------------------\n", + " Unit Performance\n", + "\n", + " Variables: \n", + "\n", + " Key : Value : Units : Fixed : Bounds\n", + " Heat Duty : -66423. : watt : False : (None, None)\n", + " Pressure Change : 0.0000 : pascal : True : (None, None)\n", + "\n", + "------------------------------------------------------------------------------------\n", + " Stream Table\n", + " Units Inlet Vapor Outlet Liquid Outlet\n", + " Total Molar Flowrate mole / second 1.9480 - - \n", + " Total Mole Fraction benzene dimensionless 0.13952 - - \n", + " Total Mole Fraction toluene dimensionless 0.039059 - - \n", + " Total Mole Fraction hydrogen dimensionless 0.18417 - - \n", + " Total Mole Fraction methane dimensionless 0.63725 - - \n", + " Temperature kelvin 763.51 - - \n", + " Pressure pascal 3.5000e+05 - - \n", + " flow_mol_phase Liq mole / second - 1.0000e-08 0.28812 \n", + " flow_mol_phase Vap mole / second - 1.6598 1.0000e-08 \n", + " mole_frac_phase_comp ('Liq', 'benzene') dimensionless - 0.75463 0.75463 \n", + " mole_frac_phase_comp ('Liq', 'toluene') dimensionless - 0.24537 0.24537 \n", + " mole_frac_phase_comp ('Vap', 'benzene') dimensionless - 0.032748 0.032748 \n", + " mole_frac_phase_comp ('Vap', 'toluene') dimensionless - 0.0032478 0.0032478 \n", + " mole_frac_phase_comp ('Vap', 'hydrogen') dimensionless - 0.21614 0.21614 \n", + " mole_frac_phase_comp ('Vap', 'methane') dimensionless - 0.74786 0.74786 \n", + " temperature kelvin - 301.88 301.88 \n", + " pressure pascal - 3.5000e+05 3.5000e+05 \n", + "====================================================================================\n" + ] + } + ], + "execution_count": 79 }, { "cell_type": "markdown", @@ -1430,32 +3175,47 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-11-20T21:46:18.106001Z", + "start_time": "2025-11-20T21:46:18.101768Z" + } + }, "source": [ - "print(\"Optimal Values\")\n", - "print()\n", + "print(\n", + " f\"\"\"Optimal Values:\n", "\n", - "print(\"H101 outlet temperature = \", value(m.fs.H101.outlet.temperature[0]), \"K\")\n", + "H101 outlet temperature = {value(m.fs.H101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"R101 outlet temperature = \", value(m.fs.R101.outlet.temperature[0]), \"K\")\n", + "R101 outlet temperature = {value(m.fs.R101.outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F101 outlet temperature = \", value(m.fs.F101.vap_outlet.temperature[0]), \"K\")\n", + "F101 outlet temperature = {value(m.fs.F101.vap_outlet.temperature[0]):.3f} K\n", "\n", - "print()\n", - "print(\"F102 outlet temperature = \", value(m.fs.F102.vap_outlet.temperature[0]), \"K\")\n", - "print(\"F102 outlet pressure = \", value(m.fs.F102.vap_outlet.pressure[0]), \"Pa\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "F102 outlet temperature = {value(m.fs.F102.vap_outlet.temperature[0]):.3f} K\n", + "F102 outlet pressure = {value(m.fs.F102.vap_outlet.pressure[0]):.3f} Pa\n", + "\"\"\"\n", + ")" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimal Values:\n", + "\n", + "H101 outlet temperature = 500.000 K\n", + "\n", + "R101 outlet temperature = 763.507 K\n", + "\n", + "F101 outlet temperature = 301.881 K\n", + "\n", + "F102 outlet temperature = 362.935 K\n", + "F102 outlet pressure = 105000.000 Pa\n", + "\n" + ] + } + ], + "execution_count": 81 } ], "metadata": { @@ -1475,7 +3235,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.12.3" } }, "nbformat": 4, diff --git a/idaes_examples/notebooks/docs/tut/core/initializing_testing.py b/idaes_examples/notebooks/docs/tut/core/initializing_testing.py new file mode 100644 index 00000000..673ccac9 --- /dev/null +++ b/idaes_examples/notebooks/docs/tut/core/initializing_testing.py @@ -0,0 +1,107 @@ +# Import required packages +from idaes.models_extra.power_generation.properties.natural_gas_PR import get_prop +from pyomo.environ import ( + ConcreteModel, + SolverFactory, + value, + units, + TransformationFactory, + Expression, +) +from idaes.core import FlowsheetBlock +from idaes.core.util.initialization import propagate_state +import idaes.logger as idaeslog +from idaes.models.properties import iapws95 +from idaes.models.unit_models import Feed +from idaes.models.unit_models.heater import Heater +from idaes.models.unit_models.heat_exchanger import ( + HeatExchanger, + delta_temperature_amtd_callback, +) +from pyomo.network import Arc, SequentialDecomposition +from idaes.core.util.model_statistics import degrees_of_freedom + +# Create the ConcreteModel and the FlowsheetBlock, and attach the flowsheet block to it. +m = ConcreteModel() + +m.fs = FlowsheetBlock(dynamic=False) + +m.fs.properties = iapws95.Iapws95ParameterBlock() + +m.fs.feed = Feed(property_package=m.fs.properties) +m.fs.heater = Heater(property_package=m.fs.properties) +m.fs.heat_exchanger = HeatExchanger( + delta_temperature_callback=delta_temperature_amtd_callback, + hot_side_name="shell", + cold_side_name="tube", + shell={"property_package": m.fs.properties}, + tube={"property_package": m.fs.properties}, +) + +m.fs.s01 = Arc(source=m.fs.feed.outlet, destination=m.fs.heat_exchanger.cold_side_inlet) +m.fs.s02 = Arc( + source=m.fs.heat_exchanger.cold_side_outlet, destination=m.fs.heater.inlet +) +m.fs.s03 = Arc( + source=m.fs.heater.outlet, destination=m.fs.heat_exchanger.hot_side_inlet +) + +TransformationFactory("network.expand_arcs").apply_to(m) +DOF_initial = degrees_of_freedom(m) +print("The initial DOF is {0}".format(DOF_initial)) + +# Fix the stream inlet conditions +m.fs.feed.flow_mol[0].fix(100) # mol/s +m.fs.feed.pressure[0].fix(101325) # Pa +m.fs.feed.enth_mol[0].fix(value(iapws95.htpx(T=293 * units.K, P=101325 * units.Pa))) + + +m.fs.heat_exchanger.overall_heat_transfer_coefficient[0].fix(500) # W/m2/K +m.fs.heat_exchanger.area.fix(50) + + +m.fs.heater.outlet.enth_mol.fix( + value(iapws95.htpx(T=1073 * units.K, P=101325 * units.Pa)) +) + +DOF_initial = degrees_of_freedom(m) +print("The DOF is {0}".format(DOF_initial)) + +# Provide initial guess for the shell inlet and create tear stream +m.fs.heat_exchanger.shell_inlet.flow_mol.fix(100) # mol/s +m.fs.heat_exchanger.shell_inlet.enth_mol[0].fix( + value(iapws95.htpx(T=1073 * units.K, P=101325 * 1.5 * units.Pa)) +) +m.fs.heat_exchanger.shell_inlet.pressure[0].fix(101325) # Pa +m.fs.s03_expanded.deactivate() + +DOF_initial = degrees_of_freedom(m) +print("The DOF is {0} after creating tear stream".format(DOF_initial)) + +m.fs.report() + +m.fs.feed.initialize(outlvl=idaeslog.INFO) +propagate_state(m.fs.s01) +m.fs.report() +m.fs.heat_exchanger.initialize(outlvl=idaeslog.INFO) +propagate_state(m.fs.s02) +m.fs.report() +m.fs.heater.initialize(outlvl=idaeslog.INFO) + +m.fs.report() + +# Solve the model +from idaes.core.solvers import get_solver + +solver = get_solver() +results = solver.solve(m, tee=False) + +# Reactivate tear stream, and unfix shell side initial conditions +m.fs.heat_exchanger.shell_inlet.flow_mol.unfix() +m.fs.heat_exchanger.shell_inlet.enth_mol[0].unfix() +m.fs.heat_exchanger.shell_inlet.pressure[0].unfix() +m.fs.s03_expanded.activate() + +results = solver.solve(m, tee=False) + +m.fs.report()