Source code for biosteam.units.design_tools.vacuum

# -*- coding: utf-8 -*-
"""
Functional algorithms for the design and purchase cost estimation of
vacuum systems.

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.
.. [2] Amazon. Robinair (15115) VacuMaster Single Stage Vacuum Pump - Single-Stage, 1.5 CFM. 
    https://www.amazon.com/Robinair-15115-VacuMaster-Single-Vacuum/dp/B005CO9FDW?ref_=ast_sto_dp.
    Accessed on 09/28/2023.
.. [3] Amazon. Robinair (15300) VacuMaster Economy Vacuum Pump - 2-Stage, 3 CFM.
    https://www.amazon.com/Robinair-15300-VacuMaster-Economy-Vacuum/dp/B000O1E5UQ?ref_=ast_sto_dp
    Accessed on 09/28/2023.

"""
from numpy import log as ln
from . import mechanical as mch
from math import ceil
from biosteam.utils import checkbounds
from biosteam.exceptions import DesignError
from numba import njit
import biosteam as bst

__all__ = ('compute_vacuum_system_power_and_cost',)


# %% Data

# System types of vacuum systems
# Volumetric flowrate ranges, (cfm) and lower limit of suction (torr)
# Rotary vane pumps based on ref. [2], [3]
_steamjet_ejectors = {
    'One stage':               ((10, 1000000), 100),
    'Two stage':               ((10, 1000000),  15),
    'Three stage':             ((10, 1000000),   2)}
_liquid_ring = {
    'One stage water seal':    (( 3,   18000),  50),
    'Two stage water seal':    (( 3,   18000),  25),
    'Oil seal':                (( 3,   18000),  10)}
_dry_vacuum = {
    'Three stage rotary lobe': ((60,     240), 1.5),
    'Three stage claw':        ((60,     270), 0.3),
    'Screw compressor':        ((50,    1400), 0.1)}
_rotary_vane = {
    'One stage':               ((0,     1.51), 0.115),
    'Two stage':               ((1.5,   3.01), 0.035)}

_default_vacuum_systems = {'Liquid-ring pump': _liquid_ring,
                           'Steam-jet ejector': _steamjet_ejectors,
                           'Dry-vacuum pump': _dry_vacuum,
                           'Rotary-vane pump': _rotary_vane}

_default_rotary_vane_work_cost = {
    'One stage': (1/5 * 0.7457, 127*1.08), # hp to kW; 2023 USD (including tax & shipping)
    'Two stage': (1/3 * 0.7457, 248*1.08)
}

_air_density = 1.2041 # kg/m3 dry air

# %% Calculate vacuum system requirements

[docs] def compute_vacuum_system_power_and_cost( F_mass, F_vol, P_suction, vessel_volume, vacuum_system_preference=None): """ Return a dictionary of vacuum system requirements. Parameters ---------- F_mass : float Vapor mass flow rate entering vacuum system from vessel in kg/hr (not including inleakage). F_vol : float Vapor volumetric flow rate entering vacuum system from vessel in m3/hr (not including inleakage). P_suction : float Suction pressure in Pa vessel_volume : float Vacuum volume in m3 vacuum_system_preference : 'Liquid-ring pump', 'Steam-jet ejector', or 'Dry-vacuum pump' Name(s) of preferred vacuum systems """ P_suction *= 7.5006e-3 # to torr if vessel_volume: vessel_volume *= 35.315 # to ft3 F_mass_air = calculate_air_inleakage(vessel_volume, P_suction) # lb/hr F_vol_air = 0.26697*F_mass_air/_air_density # cfm else: F_vol_air = F_mass_air = 0 F_vol_cfm = 0.5886*F_vol + F_vol_air # if F_vol_cfm < 3.01: # factor = 3.01/F_vol_cfm # F_vol_cfm = 3.01 # else: # factor = 1 factor = 1 F_mass_kgph = (F_mass + 0.4536*F_mass_air)*factor # kg/hr F_mass_lbph = 2.205 * F_mass_kgph vacuum_systems = get_prefered_vacuum_systems(vacuum_system_preference) name, grade, N = select_vacuum_system(vacuum_systems, F_vol_cfm, P_suction, bool(vacuum_system_preference)) base_cost = calculate_vacuum_cost(name, grade, F_mass_lbph, F_vol_cfm, P_suction) cost = bst.CE / 567. * base_cost if name == 'Steam-jet ejector': for agent in bst.HeatUtility.heating_agents: if agent.P > 689475.: break # 100 psig steam = 0.41631 * F_mass_kgph # [kmol/hr] 7.5 weight steam/ weight gas work = 0. has_condenser = grade != 'One stage' elif name == 'Rotary-vane pump': has_condenser = False agent = None steam = 0. N = 1 work = _default_rotary_vane_work_cost[grade][0] else: has_condenser = False agent = None steam = 0. work = calculate_vacuum_power(F_mass_kgph, P_suction) return {'Work': work, 'Cost': N * cost, 'Name': f"{name}, {grade.lower()}", 'In parallel': N, 'Condenser': has_condenser, 'Steam flow rate': steam, 'Heating agent': agent}
# %% Supporting functions def get_prefered_vacuum_systems(preference): defaults = _default_vacuum_systems if preference is None: return defaults else: if isinstance(preference, str): if preference not in defaults: raise ValueError(f"preference must be in the following list: {list(defaults)}") preference = (preference, *defaults) else: for name in preference: if name not in defaults: raise ValueError(f"preference must be in the following list: {list(defaults)}") return {name: defaults[name] for name in preference} def get_available_vacuum_systems(F_vol_cfm, P_suction): """ Return available vacuum type and grade Parameters ---------- F_vol_cfm : float Vapor volumetric flow rate entering vacuum system from vessel in cfm (including inleakage). P_suction : float Suction pressure in Torr """ types = [] for vacuumtype, vacuum_sys in _default_vacuum_systems.items(): for grade, flowrange_minsuction in vacuum_sys.items(): flowrange, minsuction = flowrange_minsuction if checkbounds(F_vol_cfm, flowrange) and P_suction > minsuction: types.append((vacuumtype, grade)) return types def select_vacuum_system(vacuum_systems, F_vol_cfm, P_suction, ignore_F_lb=False): """ Return a heuristic vacuum type and grade Parameters ---------- F_vol_cfm : float Vapor volumetric flow rate entering vacuum system from vessel in cfm (including inleakage). P_suction : float Suction pressure in Torr """ for name, vacuum_sys in vacuum_systems.items(): for grade, flowrange_minsuction in vacuum_sys.items(): flowrange, minsuction = flowrange_minsuction if ignore_F_lb: if F_vol_cfm < flowrange[-1] and P_suction > minsuction: return (name, grade, 1) elif checkbounds(F_vol_cfm, flowrange) and P_suction > minsuction: return (name, grade, 1) for name, vacuum_sys in vacuum_systems.items(): # Flow rate too large for grade, flowrange_minsuction in vacuum_sys.items(): flowrange, minsuction = flowrange_minsuction if P_suction > minsuction: N = ceil(F_vol_cfm / flowrange[-1]) return (name, grade, N) raise DesignError(f'no vacuum system available at current flow ({F_vol_cfm:.2f} cfm) and suction pressure ({P_suction:.2f} Torr)') @njit(cache=True) def calculate_heuristic_air_inleakage(V, P): """ Return air in-leakage in kg/hr through a heuristic calculation. Parameters ---------- V : float Vacuum volume in m3 P : float Suction pressure in Pa """ if P > 11999.013: k = 0.2 elif P > 4132.993: k = 0.15 elif P > 2799.77: k = 0.10 elif P > 133.322: k = 0.051 else: raise ValueError('cannot calculate air inleakage at pressures lower than 133.32 Pascal') return k*V**0.667 @njit(cache=True) def calculate_air_inleakage(V, P): """ Return air in-leakage in kg/hr. Parameters ---------- V : float Vacuum volume in ft3 P : float Suction pressure in Torr """ lnP = ln(P) return 5. + (0.0298 + 0.03088*lnP - 5.733e-4*lnP*lnP)*V**0.66 def calculate_vacuum_power(F_mass, P_suction): """ Return vacuum power (after accounting for motor efficiency) in kW. Parameters ---------- F_mass : float Total mass flow rate entering vacuum system in kg/hr (including inleakage). P_suction : float Suction pressure in Torr """ SF = F_mass/P_suction # Size factor if SF < 0.2: SF = 0.2 elif SF > 16.: SF = 16. Pb = 21.4*SF**0.924 # Break power assuming Liquid-ring (NASH) mu_m = mch.motor_efficiency(Pb) return Pb/mu_m def calculate_vacuum_cost(vacuum_sys, grade, F_mass_lbph, F_vol_cfm, P_suction): # Costing for different vacuums ASSUMING THAT ALL ARE CARBON STEEL!!!! if vacuum_sys == 'Steam-jet ejector': S = F_mass_lbph/P_suction Cp = 1915*S**0.41 if grade == 'One stage': Cs = 1 elif grade == 'Two stage': Cs = 1.8 * 1.6 # 2 stage + 1 condenser elif grade == 'Three stage': Cs = 2.1 * 2.3 # 3 stage + 2 condenser Cost = Cp*Cs elif vacuum_sys == 'Liquid-ring pump': S = F_vol_cfm Cp = 8250*S**0.37 if grade == 'One stage water seal': Cs = 1 elif grade == 'Two stage water seal': Cs = 1.8 elif grade == 'Oil seal': Cs = 2.1 Cost = Cp*Cs elif vacuum_sys == 'Dry-vacuum pump': S = F_vol_cfm if grade == 'Three stage rotary lobe': Cp = 8075*S**0.41 elif grade == 'Three stage claw': Cp = 9785*S**0.36 elif grade == 'Screw compressor': Cp = 10875*S**0.38 Cost = Cp elif vacuum_sys == 'Rotary-vane pump': Cost = _default_rotary_vane_work_cost[grade][1] / 708. * 567. # !!! 708 is the 2021 CEPCI, need to be updated to 2023 CEPCI return Cost