Mixer Unit Model with Ideal Property Package
Contents
###############################################################################
# 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-2023 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.
###############################################################################
Mixer Unit Model with Ideal Property Package#
Learning Outcomes#
Demonstrate use of the Mixer unit model in IDAES
Demonstrate different options available
Problem Statement#
In this example, we will be mixing liquid benzene and liquid toluene streams to form a mixture. The inlet conditions are as follows:
Stream 1:
Benzene Flow Rate = 100 mol/s
Pressure = 101325 Pa
Temperature = 353 K
Stream 2
Toluene Flow Rate = 100 mol/s
Pressure = 202650 Pa
Temperature = 356 K
We will look at two cases in this tutorial:
Case 1: Specify the number of inlets to the mixer, and set the
momentum_mixingtype set to “minimize”Case 2: Specify the inlet names, and set
momentum_mixingtype set to “equality” (in this case, pressure will be specified for only one inlet stream)
Note: When the momentum mixing type is set to ‘minimize’, the mixed stream pressure takes the minimum value among all inlet stream pressures. When the momentum mixing type is set to ‘equality’, the mixed stream, along with all inlet streams have the same value of pressure.
For more details, please refer to the IDAES documentation: https://idaes-pse.readthedocs.io/en/stable
Setting up the problem in IDAES#
In the following cell, we will be importing the necessary components from Pyomo and IDAES.
# Import objects from pyomo package
from pyomo.environ import ConcreteModel, SolverFactory, value
# Import the main FlowsheetBlock from IDAES. The flowsheet block will contain the unit model
from idaes.core import FlowsheetBlock
# Import the mixer unit model
from idaes.models.unit_models import Mixer, MomentumMixingType
# Import idaes logger to set output levels
import idaes.logger as idaeslog
# Import the BTX_ideal property package to create a properties block for the flowsheet
from idaes.models.properties.activity_coeff_models import BTX_activity_coeff_VLE
# Import the degrees_of_freedom function from the idaes.core.util.model_statistics package
# DOF = Number of Model Variables - Number of Model Constraints
from idaes.core.util.model_statistics import degrees_of_freedom
# Create the ConcreteModel and the FlowsheetBlock objects, and attach the flowsheet block to it.
m = ConcreteModel()
m.fs = FlowsheetBlock(
dynamic=False
) # dynamic or ss flowsheet needs to be specified here
# Add properties parameter block to the flowsheet with specifications
m.fs.properties = BTX_activity_coeff_VLE.BTXParameterBlock(
valid_phase="Liq", activity_coeff_model="Ideal"
)
Case 1:#
Specify the number of inlets to the mixer, and set the momentum_mixing type set to “minimize”.
# Create an instance of the mixer unit, attaching it to the flowsheet
# Specify that the property package to be used with the mixer is the
# one we created earlier, the number of mixer inlets is 2, and momentum
# mixing type is minimize
m.fs.mixer_1 = Mixer(
property_package=m.fs.properties,
num_inlets=2,
momentum_mixing_type=MomentumMixingType.minimize,
)
# Call the degrees_of_freedom function, get initial DOF
DOF_initial = degrees_of_freedom(m)
print("The initial degrees of freedom is: {0}".format(DOF_initial))
For case 1, we chose to specify only the number of inlets and names were not specified. When this option is selected, the inlets are named as “inlet_1”, “inlet_2” and so on depending on the number of inlets specified. In the following cell, we will use this naming convention to specify the inlet conditions.
# Fix the inlet conditions
# Benzene stream
m.fs.mixer_1.inlet_1.flow_mol.fix(100) # converting to mol/s as unit basis is mol/s
m.fs.mixer_1.inlet_1.mole_frac_comp[0, "benzene"].fix(1)
m.fs.mixer_1.inlet_1.mole_frac_comp[0, "toluene"].fix(0)
m.fs.mixer_1.inlet_1.pressure.fix(101325) # Pa
m.fs.mixer_1.inlet_1.temperature.fix(353) # K
# Toluene stream
m.fs.mixer_1.inlet_2.flow_mol.fix(100) # converting to mol/s as unit basis is mol/s
m.fs.mixer_1.inlet_2.mole_frac_comp[0, "benzene"].fix(0)
m.fs.mixer_1.inlet_2.mole_frac_comp[0, "toluene"].fix(1)
m.fs.mixer_1.inlet_2.pressure.fix(202650) # Pa
m.fs.mixer_1.inlet_2.temperature.fix(356) # K
# Call the degrees_of_freedom function, get final DOF
DOF_final = degrees_of_freedom(m)
print("The final degrees of freedom is: {0}".format(DOF_final))
Flowsheet Initialization#
# Initialize the flowsheet, and set the output at WARNING
m.fs.mixer_1.initialize(outlvl=idaeslog.WARNING)
Obtaining Simulation Results#
# Solve the simulation using ipopt
# Note: If the degrees of freedom = 0, we have a square problem
opt = SolverFactory("ipopt")
result = opt.solve(m, tee=True)
View Results#
# Display output report
m.fs.mixer_1.report()
Case 2#
For case 2, we will specify the inlet names for the two inlets, and set momentum_mixing type set to “equality” (in this case, pressure will be specified for only one inlet stream). We will name the 2 inlets as “benzene_inlet” and “toluene_inlet”.
# Create an instance of another mixer unit, attaching it to the same flowsheet.
# Specify that the property package to be used with the mixer is the one we created earlier,
# inlet list is specified but names are specified, and momentum mixing type is equality
m.fs.mixer_2 = Mixer(
property_package=m.fs.properties,
inlet_list=["benzene_inlet", "toluene_inlet"],
momentum_mixing_type=MomentumMixingType.equality,
)
# Check the required degrees of freedom
DOF_init = degrees_of_freedom(m.fs.mixer_2)
print("The initial degrees of freedom is: {0}".format(DOF_init))
We see that the degrees of freedom has dropped by 1 to 9 when compared with case 1. This is because we selected the momentum_mixing_type as MomentumMixingType.equality which basically adds a constraint that equates the pressure between all inlets and the outlet. Therefore, when we specify the inlet confitions in the next cell, we will define the pressure for only the benzene_inlet stream.
# Fix the stream inlet conditions
# Benzene stream
m.fs.mixer_2.benzene_inlet.flow_mol.fix(
100
) # converting to mol/s as unit basis is mol/s
m.fs.mixer_2.benzene_inlet.mole_frac_comp[0, "benzene"].fix(1)
m.fs.mixer_2.benzene_inlet.mole_frac_comp[0, "toluene"].fix(0)
m.fs.mixer_2.benzene_inlet.pressure.fix(
101325
) # Pa , Another option is m1.fs.mixer2.inlet2.pressure.fix(202650)
m.fs.mixer_2.benzene_inlet.temperature.fix(353) # K
# Toluene stream
m.fs.mixer_2.toluene_inlet.flow_mol.fix(
100
) # converting to mol/s as unit basis is mol/s
m.fs.mixer_2.toluene_inlet.mole_frac_comp[0, "benzene"].fix(0)
m.fs.mixer_2.toluene_inlet.mole_frac_comp[0, "toluene"].fix(1)
m.fs.mixer_2.toluene_inlet.temperature.fix(356) # K
DOF_final = degrees_of_freedom(m.fs.mixer_2)
print("The final degrees of freedom is: {0}".format(DOF_final))
Flowsheet Initialization#
# Initialize the flowsheet, and set the output at WARNING
m.fs.mixer_2.initialize(outlvl=idaeslog.WARNING)
Obtaining Simulation Results#
# Solve the simulation using ipopt
# Note: If the degrees of freedom = 0, we have a square problem
opt = SolverFactory("ipopt")
result = opt.solve(m.fs.mixer_2, tee=True)
View Results#
# Display a readable report
m.fs.mixer_2.report()