Source code for biosteam.units.vacuum_system

# -*- coding: utf-8 -*-
# BioSTEAM: The Biorefinery Simulation and Techno-Economic Analysis Modules
# Copyright (C) 2020-2023, Yoel Cortes-Pena <yoelcortes@gmail.com>
# 
# This module is under the UIUC open-source license. See 
# github.com/BioSTEAMDevelopmentGroup/biosteam/blob/master/LICENSE.txt
# for license details.
"""
.. contents:: :local:

.. autoclass:: biosteam.units.vacuum_system.VacuumSystem

"""
from . import design_tools as design
from .auxiliary import Auxiliary
from typing import Optional, Union
import biosteam as bst
from .._unit import Unit

__all__ = ('VacuumSystem',)
       
[docs] class VacuumSystem(Auxiliary): """ Create an auxiliary vacuum system for a unit operation. Parameters ---------- unit : Main unit operation containing the auxiliary vacuum system. Missing parameters are estimated through this unit operation, if given. F_mass : Vapor mass flow rate entering vacuum system from vessel [kg/hr] (not including inleakage). Defaults to the vapor volumetric flow rate exiting `unit`. F_vol : Vapor volumetric flow rate entering vacuum system from vessel [m3/hr] (not including inleakage). Defaults to the vapor mass flow rate exiting `unit`. P_suction : Suction pressure [Pa]. Defaults to `unit.P` or the minimum outlet pressure. vessel_volume : Vacuum volume [m3]. Defaults to `unit.design_results['Total volume']`. vacuum_system_preference : Name(s) of preferred vacuum systems. Valid names include 'Liquid-ring pump', 'Steam-jet ejector', and 'Dry-vacuum pump'. Notes ----- The vacuum system is sized/costed based on the vapor flow rate through the vacuum system, which includes the inleakage into the vessel through fixtures and cracks. The inleakage is a function of the suction pressure and the total vessel volume as in [1]_. BioSTEAM's CSTR, Flash, and Distillation columns automatically include a vacuum system when needed. Examples -------- Create vessel with a vacuum system: >>> import biosteam as bst >>> class VacuumVessel(bst.Unit): ... auxiliary_unit_names = ('vacuum_system',) # Mark attributes as auxiliary ... _units = {'Total volume': 'm3'} # This is needed for the vacuum system ... P = 1000 # Pa ... tau = 4 # hr ... ... def _run(self): ... self.outs[0].P = 1000 # Pa ... ... def _design(self): ... self.design_results['Total volume'] = self.feed.F_vol * self.tau ... self.vacuum_system = bst.VacuumSystem(self) ... >>> bst.settings.set_thermo(['Water']) >>> feed = bst.Stream('feed', Water=1e6) >>> V1 = VacuumVessel('V1', ins=feed) >>> V1.simulate() >>> V1.results() Vacuum vessel Units V1 Medium pressure steam Duty kJ/hr 1.04e+07 Flow kmol/hr 288 Cost USD/hr 79.3 Cooling water Duty kJ/hr -9.37e+06 Flow kmol/hr 6.4e+03 Cost USD/hr 3.12 Design Total volume m3 7.23e+04 Purchase cost Vacuum system - Steam-jet ejecto... USD 8.18e+04 Total purchase cost USD 8.18e+04 Utility cost USD/hr 82.4 For simplicity, this example does not include the cost of the vessel, but vessel costs should be included for techno-economic analysis. References ---------- .. [1] Seider, W. D.; Lewin, D. R.; Seader, J. D.; Widagdo, S.; Gani, R.; Ng, M. K. Cost Accounting and Capital Cost Estimation. In Product and Process Design Principles; Wiley, 2017; pp 426–485. """ __slots__ = ( 'power_utility', 'heat_utilities', 'baseline_purchase_costs', 'purchase_costs', 'installed_costs', 'F_M', 'F_D', 'F_P', 'F_BM', 'owner', ) def __init__(self, unit: Optional[Unit]=None, vacuum_system_preference: Optional[str]=None, F_mass: Optional[float]=None, F_vol: Optional[float]=None, P_suction: Optional[float]=None, vessel_volume: Optional[Union[float, list[float]]]=None ): super().__init__() if unit: # Deduce arguments if unit given if F_mass is None or F_vol is None: # If vapor is condensed, assume vacuum system is after condenser vents = [i for i in unit.outs if 'g' in i.phase] F_mass = 0. F_vol = 0. for vapor in vents: hx = vapor.sink if isinstance(hx, bst.HX): index = hx.ins.index(vapor) vapor = hx.outs[index] if 'g' not in vapor.phase: continue if isinstance(vapor, bst.MultiStream): F_mass += vapor['g'].F_mass F_vol += vapor['g'].F_vol else: F_mass += vapor.F_mass F_vol += vapor.F_vol if P_suction is None: P_suction = getattr(unit, 'P', None) or getattr(unit, 'P_suction', None) if P_suction is None: P_suction = min([i.P for i in unit.outs]) if vessel_volume is None: if 'Total volume' in unit.design_results: vessel_volume = unit.get_design_result('Total volume', 'm3') else: raise ValueError("'Total volume' was not found in design results; " "'vessel_volume' parameter could not be deduced") else: # In case user does not supply all arguments params = [('F_mass', F_mass), ('F_vol', F_vol), ('P_suction', P_suction), ('vessel_volume', vessel_volume)] for name, value in params: if value is None: raise ValueError( f"missing argument '{name}'; cannot deduce '{name}'" "when no unit is specified" ) capex = self.baseline_purchase_costs # Assume all costs the same vacuum_results = design.compute_vacuum_system_power_and_cost( F_mass, F_vol, P_suction, vessel_volume, vacuum_system_preference ) name = vacuum_results['Name'] capex[name] = vacuum_results['Cost'] heating_agent = vacuum_results['Heating agent'] if heating_agent: # Steam turbine vacuum_steam = self.create_heat_utility() vacuum_steam.set_utility_by_flow_rate(heating_agent, vacuum_results['Steam flow rate']) if vacuum_results['Condenser']: self.add_heat_utility(-vacuum_steam.unit_duty, 373.15) # Vacuum cooling water self.add_power_utility(vacuum_results['Work'])