###############################################################################
# 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.
###############################################################################

Compressor Unit Model with Span-Wagner Property Package for supercritical CO2#

Learning Outcomes#

  • Demonstrate use of the compressor unit model in IDAES

  • Demonstarte use of the Span Wagner EOS for supercritical CO2 cycles

  • Demonstrate different simulation options available for the compressor unit model

In this tutorial, we will simulate the main compressor for an indirect supercritical CO2 cycle using the Span-Wagner EOS as the property package. The input specifications for this tutorial are from the NETL report on indirect SCO2 cycles available here. In this example, we will be compressing supercritical CO2 from 9.1 MPa to 34.5 MPa.

It is assumed that the compressor operates at steady state.

The inlet specifications are as follows:

  • Flow Rate = 91067 mol/s

  • Pressure = 9.1107 MPa

  • Temperature = 308.15 K

We will simulate 2 different cases, depending on the compressor specifications fixed by the user:

Case 1: In this case, we will fix the isentropic efficiency and the pressure change across the compressor.

  • Pressure Change = 25.51 MPa

  • Isentropic Efficiency = 0.85

Case 2: In this case, we will fix the isentropic efficiency and the pressure ratio instead of the pressure change across the compressor.

  • Pressure Ratio = 3.8

  • Isentropic Efficiency = 0.85

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, units

# Import the main FlowsheetBlock from IDAES. The flowsheet block will contain the unit model
from idaes.core import FlowsheetBlock

# Import idaes logger to set output levels
import idaes.logger as idaeslog

# Create the ConcreteModel and the FlowsheetBlock, and attach the flowsheet block to it.
m = ConcreteModel()

m.fs = FlowsheetBlock(
    dynamic=False
)  # dynamic or ss flowsheet needs to be specified here


# Import the SWCO2 property package to create a properties block for the flowsheet
from idaes.models.properties.swco2 import SWCO2ParameterBlock, StateVars, htpx

# Add properties parameter block to the flowsheet with specifications
m.fs.properties = SWCO2ParameterBlock()

Case 1: Fix pressure change and isentropic efficiency#

Add Compressor Unit Model#

# Import compressor unit model from the model library
from idaes.models.unit_models.pressure_changer import (
    PressureChanger,
    ThermodynamicAssumption,
)

# Create an instance of the compressor unit, attaching it to the flowsheet
# Specify that the property package to be used with the compressor is the one we created earlier.
m.fs.compr_case_1 = PressureChanger(
    dynamic=False,
    property_package=m.fs.properties,
    compressor=True,
    thermodynamic_assumption=ThermodynamicAssumption.isentropic,
)

# 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

# Call the degrees_of_freedom function, get intitial DOF
DOF_initial = degrees_of_freedom(m)
print("The initial DOF is {0}".format(DOF_initial))

Fix Inlet Stream Conditions#

# Fix the stream inlet conditions
m.fs.compr_case_1.inlet.flow_mol[0].fix(91067)  # mol/s

# Use htpx method to obtain the molar enthalpy of inlet stream at the given temperature and pressure conditions
m.fs.compr_case_1.inlet.enth_mol[0].fix(
    value(htpx(T=308.15 * units.K, P=9.1107e06 * units.Pa))
)  # T in K, P in Pa
m.fs.compr_case_1.inlet.pressure[0].fix(9.1107e06)

Fix Pressure Change and Isentropic Efficiency#

# Fix compressor conditions
m.fs.compr_case_1.deltaP.fix(2.5510e07)
m.fs.compr_case_1.efficiency_isentropic.fix(0.85)

# Call the degrees_of_freedom function, get final DOF
DOF_final = degrees_of_freedom(m)
print("The final DOF is {0}".format(DOF_final))

Initialization#

# Initialize the flowsheet, and set the output at INFO level
m.fs.compr_case_1.initialize(outlvl=idaeslog.INFO)

Solve Model#

# Solve the simulation using ipopt
# Note: If the degrees of freedom = 0, we have a square problem
opt = SolverFactory("ipopt")
solve_status = opt.solve(m, tee=True)

View Results#

# Display Outlet Pressure
m.fs.compr_case_1.outlet.pressure.display()
# Display a readable report
m.fs.compr_case_1.report()

Case 2: Fix pressure ratio and isentropic efficiency#

Add Compressor Unit#

# Create an instance of another compressor unit, attaching it to the flowsheet
# Specify that the property package to be used with the turbine is the one we created earlier.
m.fs.compr_case_2 = PressureChanger(
    dynamic=False,
    property_package=m.fs.properties,
    compressor=True,
    thermodynamic_assumption=ThermodynamicAssumption.isentropic,
)

# Call the degrees_of_freedom function, get intitial DOF
DOF_initial = degrees_of_freedom(m.fs.compr_case_2)
print("The initial DOF is {0}".format(DOF_initial))

Fix Inlet Stream Conditions#

# Fix the stream inlet conditions
m.fs.compr_case_2.inlet.flow_mol[0].fix(
    91067
)  # converting to mol/s as unit basis is mol/s

# Use htpx method to obtain the molar enthalpy of inlet stream at the given temperature and pressure conditions
m.fs.compr_case_2.inlet.enth_mol[0].fix(
    value(htpx(T=308.15 * units.K, P=9.1107e06 * units.Pa))
)
m.fs.compr_case_2.inlet.pressure[0].fix(9.1107e06)

Fix Compressor Pressure Ratio and Isentropic Efficiency#

# Fix compressor pressure ratio
m.fs.compr_case_2.ratioP.fix(3.8)

# Fix compressor efficiency
m.fs.compr_case_2.efficiency_isentropic.fix(0.85)

# Call the degrees_of_freedom function, get final DOF
DOF_final = degrees_of_freedom(m.fs.compr_case_2)
print("The final DOF is {0}".format(DOF_final))

Initialization#

# Initialize the flowsheet, and set the output at INFO level
m.fs.compr_case_2.initialize(outlvl=idaeslog.INFO)

Solve Model#

# Solve the simulation using ipopt
# Note: If the degrees of freedom = 0, we have a square problem
opt = SolverFactory("ipopt")
solve_status = opt.solve(m.fs.compr_case_2, tee=True)

View Results#

# Display compressor pressure increase
m.fs.compr_case_2.outlet.pressure[0].display()
# Display a readable report
m.fs.compr_case_2.report()