Source code for idaes.models.plug_flow_reactor

##############################################################################
# Institute for the Design of Advanced Energy Systems Process Systems
# Engineering Framework (IDAES PSE Framework) Copyright (c) 2018, 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.txt and LICENSE.txt for full copyright and
# license information, respectively. Both files are also available online
# at the URL "https://github.com/IDAES/idaes".
##############################################################################
"""
Basic IDAES plug flow reactor model.
"""
from __future__ import division

# Import Python libraries
import logging

# Import Pyomo libraries
from pyomo.environ import Constraint, Var
from pyomo.common.config import ConfigValue, In

# Import IDAES cores
from idaes.core import UnitBlockData, declare_process_block_class, \
                        Holdup1D, CONFIG_Base
from idaes.core.util.config import is_parameter_block, list_of_strings
from idaes.core.util.misc import add_object_ref

__author__ = "Andrew Lee"


# Set up logger
logger = logging.getLogger('idaes.unit_model')


[docs]@declare_process_block_class("PFR") class PFRData(UnitBlockData): """ Compressor/Expander Unit Class """ CONFIG = CONFIG_Base() # Set default values of inherited attributes CONFIG.get('include_holdup')._default = False CONFIG.get("material_balance_type")._default = 'component_phase' CONFIG.get("energy_balance_type")._default = 'total' CONFIG.get("momentum_balance_type")._default = 'total' CONFIG.get("has_rate_reactions")._default = True CONFIG.get("has_equilibrium_reactions")._default = True CONFIG.get("has_phase_equilibrium")._default = False CONFIG.get("has_mass_transfer")._default = False CONFIG.get("has_heat_transfer")._default = False CONFIG.get("has_work_transfer")._default = False CONFIG.get("has_pressure_change")._default = False # Add unit model attributes CONFIG.declare("property_package", ConfigValue( default=None, domain=is_parameter_block, description="Property package to use for holdup", doc="""Property parameter object used to define property calculations (default = 'use_parent_value') - 'use_parent_value' - get package from parent (default = None) - a ParameterBlock object""")) CONFIG.declare("property_package_args", ConfigValue( default={}, description="Arguments to use for constructing property packages", doc="""A dict of arguments to be passed to the PropertyBlockData and used when constructing these (default = 'use_parent_value') - 'use_parent_value' - get package from parent (default = None) - a dict (see property package for documentation)""")) CONFIG.declare("inlet_list", ConfigValue( domain=list_of_strings, description="List of inlet names", doc="""A list containing names of inlets (default = None) - None - default single inlet - list - a list of names for inlets""")) CONFIG.declare("num_inlets", ConfigValue( domain=int, description="Number of inlets to unit", doc="""Argument indication number (int) of inlets to construct (default = None). Not used if inlet_list arg is provided. - None - use inlet_list arg instead - int - Inlets will be named with sequential numbers from 1 to num_inlets""")) CONFIG.declare("outlet_list", ConfigValue( domain=list_of_strings, description="List of outlet names", doc="""A list containing names of outlets (default = None) - None - default single outlet - list - a list of names for outlets""")) CONFIG.declare("num_outlets", ConfigValue( domain=int, description="Number of outlets to unit", doc="""Argument indication number (int) of outlets to construct (default = None). Not used if outlet_list arg is provided. - None - use outlet_list arg instead - int - Outlets will be named with sequential numbers from 1 to num_outlets""")) CONFIG.declare("discretization_method", ConfigValue( default='OCLR', domain=In(['OCLR', 'OCLL', 'BFD', 'FFD']), description="Discretization method to apply to length domain", doc="""Method to be used by DAE transformation when discretizing length domain (default = `OCLR`). - 'OCLR' - orthogonal collocation (Radau roots) - 'OCLL' - orthogonal collocation (Legendre roots) - 'BFD' - backwards finite difference (1st order) - 'FFD' - forwards finite difference (1st order)""")) CONFIG.declare("finite_elements", ConfigValue( default=20, domain=int, description="Number of finite elements length domain", doc="""Number of finite elements to use when discretizing length domain (default=20)""")) CONFIG.declare("collocation_points", ConfigValue( default=3, domain=int, description="Number of collocation points per finite element", doc="""Number of collocation points to use per finite element when discretizing length domain (default=3)""")) CONFIG.declare("has_mass_diffusion", ConfigValue( default=False, domain=In([True, False]), description="Mass diffusion flag", doc="""Flag indicating whether mass diffusion/dispersion should be included in material balance equations (default=False)""")) CONFIG.declare("has_energy_diffusion", ConfigValue( default=False, domain=In([True, False]), description="Energy diffusion flag", doc="""Flag indicating whether energy diffusion/dispersion should be included in energy balance equations (default=False)""")) CONFIG.declare("has_velocity", ConfigValue( default=False, domain=In([True, False]), description="Velocity calculation flag", doc="""Flag indicating whether velocity should be include in the model (default=False)"""))
[docs] def build(self): """ Begin building model (pre-DAE transformation). Args: None Returns: None """ # Call UnitModel.build to setup dynamics super(PFRData, self).build() # Build Holdup Block self.holdup = Holdup1D( discretization_method=self.config.discretization_method, finite_elements=self.config.finite_elements, collocation_points=self.config.collocation_points, has_mass_diffusion=self.config.has_mass_diffusion, has_energy_diffusion=self.config.has_energy_diffusion) # Set Unit Geometry and holdup Volume self._set_geometry() # Construct performance equations self._make_performance()
[docs] def post_transform_build(self): """ Continue model construction after DAE transformation. Args: None Returns: None """ # Construct Inlets self.build_inlets(inlets=self.config.inlet_list, num_inlets=self.config.num_inlets) # Build Outlets self.build_outlets(outlets=self.config.outlet_list, num_outlets=self.config.num_outlets)
def _set_geometry(self): """ Define the geometry of the unit as necessary, and link to holdup volume Args: None Returns: None """ # Create references to all geometry variables add_object_ref(self, "volume", self.holdup.volume) add_object_ref(self, "area", self.holdup.area) add_object_ref(self, "length", self.holdup.length) # Create reference to spatial domain add_object_ref(self, "ldomain", self.holdup.ldomain) # Create velcoity Var and Constraints if required if self.config.has_velocity is True: self.velocity = Var(self.time, self.ldomain, initialize=1, doc="Material velocity within reactor") @self.Constraint(self.time, self.ldomain, doc="Velocity calculation") def velocity_calculation(b, t, x): return (b.velocity[t, x]*b.area == b.holdup.properties[t, x].flow_vol) if hasattr(self.holdup.properties[0, 1], "velocity"): @self.Constraint(self.time, self.ldomain, doc="Link velocity to properties") def link_velocity(b, t, x): if hasattr(b.holdup.properties[t, x], "velocity"): return (b.velocity[t, x] == b.holdup.properties[t, x].velocity) else: return Constraint.Skip def _make_performance(self): """ Define constraints which describe the behaviour of the unit model. Args: None Returns: None """ # Add constraint relating extents to rate of reaction if hasattr(self.holdup, "rate_reaction_idx"): add_object_ref(self, "rate_reaction_idx", self.holdup.rate_reaction_idx) @self.Constraint(self.time, self.ldomain, self.rate_reaction_idx, doc="Extents of reaction") def rate_reaction_extents(b, t, x, k): return b.holdup.rate_reaction_extent[t, x, k] == ( b.area*b.holdup.properties[t, x].reaction_rate[k]) # Set references to balance terms at unit level if (self.config.has_heat_transfer is True and self.config.energy_balance_type != 'none'): add_object_ref(self, "heat", self.holdup.heat) if (self.config.has_pressure_change is True and self.config.momentum_balance_type != 'none'): add_object_ref(self, "deltaP", self.holdup.deltaP)