class PhysicalParameterData(PhysicalParameterBlock): """ Property Parameter Block Class. """ # Config block for the _IdealStateBlock CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "valid_phase", ConfigValue(default=('Vap', 'Liq'), domain=In(['Liq', 'Vap', ('Vap', 'Liq'), ('Liq', 'Vap')]), description="Flag indicating the valid phase", doc="""Flag indicating the valid phase for a given set of conditions, and thus corresponding constraints should be included, **default** - ('Vap', 'Liq'). **Valid values:** { **'Liq'** - Liquid only, **'Vap'** - Vapor only, **('Vap', 'Liq')** - Vapor-liquid equilibrium, **('Liq', 'Vap')** - Vapor-liquid equilibrium,}""")) CONFIG.declare( "Cp", ConfigValue( default=0.035, domain=float, description="Constant pressure heat capacity in MJ/(kgmol K)", doc="""Value for the constant pressure heat capacity, **default** = 0.035 MJ/(kgmol K)""")) def build(self): ''' Callable method for Block construction. ''' super(PhysicalParameterData, self).build() self.state_block_class = IdealStateBlock # List of valid phases in property package # List of valid phases in property package if self.config.valid_phase == ('Liq', 'Vap') or \ self.config.valid_phase == ('Vap', 'Liq'): self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True) elif self.config.valid_phase == 'Liq': self.phase_list = Set(initialize=['Liq']) else: self.phase_list = Set(initialize=['Vap']) self.component_list = Set(initialize=['CH4', 'CO', 'H2', 'CH3OH']) # List of components in each phase (optional) self.phase_comp = { "Liq": self.component_list, "Vap": self.component_list } self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4]) self.phase_equilibrium_list = \ {1: ["CH4", ("Vap", "Liq")], 2: ["CO", ("Vap", "Liq")], 3: ["H2", ("Vap", "Liq")], 4: ["CH3OH", ("Vap", "Liq")]} # Gas Constant self.gas_constant = Param(within=NonNegativeReals, mutable=False, default=0.008314, doc='Gas Constant [MJ/(kgmol.K)]') self.vapor_pressure_coeff = { ('CH4', 'A'): 15.2243, ('CH4', 'B'): 897.84, ('CH4', 'C'): -7.16, ('CO', 'A'): 14.3686, ('CO', 'B'): 530.22, ('CO', 'C'): -13.15, ('H2', 'A'): 13.6333, ('H2', 'B'): 164.9, ('H2', 'C'): 3.19, ('CH3OH', 'A'): 18.5875, ('CH3OH', 'B'): 3626.55, ('CH3OH', 'C'): -34.29 } Cp = self.config.Cp Cv = Cp - self.gas_constant.value gamma = Cp / Cv self.gamma = Param(within=NonNegativeReals, mutable=True, default=gamma, doc='Ratio of Cp to Cv') self.Cp = Param(within=NonNegativeReals, mutable=True, default=Cp, doc='Constant pressure heat capacity [MJ/(kgmol K)]') @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mol': { 'method': None, 'units': 'kgmol/s' }, 'mole_frac': { 'method': None, 'units': 'no unit' }, 'temperature': { 'method': None, 'units': '100K' }, 'pressure': { 'method': None, 'units': 'MPa' }, 'flow_mol_phase': { 'method': None, 'units': 'kgmol/s' }, 'density_mol': { 'method': '_density_mol', 'units': 'kgmol/m^3' }, 'vapor_pressure': { 'method': '_vapor_pressure', 'units': 'MPa' }, 'mole_frac_phase': { 'method': '_mole_frac_phase', 'units': 'no unit' }, 'enthalpy_comp_liq': { 'method': '_enthalpy_comp_liq', 'units': 'MJ/kgmol' }, 'enthalpy_comp_vap': { 'method': '_enthalpy_comp_vap', 'units': 'MJ/kgmol' }, 'enthalpy_liq': { 'method': '_enthalpy_liq', 'units': 'MJ/kgmol' }, 'enthalpy_vap': { 'method': '_enthalpy_vap', 'units': 'MJ/kgmol' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'kg', 'amount': 'kgmol', 'temperature': '100K', 'energy': 'MJ', 'holdup': 'kgmol' })
class ETOHParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(ETOHParameterData, self).build() self._state_block_class = IdealStateBlock self.ethanol = Component() self.water = Component() self.CO2 = Component() #self.hydrogen = Component() self.Liq = LiquidPhase() self.Vap = VaporPhase() # List of components in each phase (optional) self.phase_comp = { "Liq": self.component_list, "Vap": self.component_list } # List of phase equilibrium index self.phase_equilibrium_idx = Set(initialize=[1, 2, 3]) self.phase_equilibrium_list = \ {1: ["ethanol", ("Vap", "Liq")], # 2: ["water", ("Vap", "Liq")], 3: ["CO2", ("Vap", "Liq")]} #4: ["methane", ("Vap", "Liq")], #5: ["diphenyl", ("Vap", "Liq")]} # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, doc='Reference pressure [Pa]') self.temperature_ref = Param(mutable=True, default=298.15, doc='Reference temperature [K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid pressure_crit_data = {'ethanol': 63e5, 'water': 220.5e5, 'CO2': 73.8e5} self.pressure_crit = Param(self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(pressure_crit_data), doc='Critical pressure [Pa]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid temperature_crit_data = { 'ethanol': 515.15, 'water': 647.15, 'CO2': 304.34 } self.temperature_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(temperature_crit_data), doc='Critical temperature [K]') # Gas Constant self.gas_const = Param(within=NonNegativeReals, mutable=False, default=8.314, doc='Gas Constant [J/mol.K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid mw_comp_data = { 'ethanol': 46.07E-3, 'water': 18.02E-3, 'CO2': 44.01e-3 } self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight Kg/mol") # Constants for liquid densities # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) dens_liq_data = { ('ethanol', '1'): 1.048, #todo ('ethanol', '2'): 0.27627, ('ethanol', '3'): 513.92, ('ethanol', '4'): 0.2331, ('water', '1'): 5.459, ('water', '2'): 0.30542, ('water', '3'): 647.13, ('water', '4'): 0.081, ('CO2', '1'): 2.768, ('CO2', '2'): 0.26212, ('CO2', '3'): 304.21, ('CO2', '4'): 0.2908 } self.dens_liq_params = Param( self.component_list, ['1', '2', '3', '4'], mutable=False, initialize=extract_data(dens_liq_data), doc="Parameters to compute liquid densities") # Boiling point at standard pressure # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) bp_data = {('ethanol'): 351.52, ('water'): 373.15, ('CO2'): 194.69} self.temperature_boil = Param( self.component_list, mutable=False, initialize=extract_data(bp_data), doc="Pure component boiling points at standard pressure [K]") # Constants for specific heat capacity, enthalpy # Sources: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid # Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) # Unit: J/kmol-K cp_ig_data = { ('Liq', 'ethanol', '1'): 1.2064E5, #todo ('Liq', 'ethanol', '2'): -1.3963E2, ('Liq', 'ethanol', '3'): -3.0341E-2, ('Liq', 'ethanol', '4'): 2.0386E-3, ('Liq', 'ethanol', '5'): 0, ('Vap', 'ethanol', '1'): 36.548344E3, ('Vap', 'ethanol', '2'): 5.221192, ('Vap', 'ethanol', '3'): 0.46109444, ('Vap', 'ethanol', '4'): -0.000583975, ('Vap', 'ethanol', '5'): 2.20986E-07, ('Liq', 'water', '1'): 2.7637E5, #reference: toluene 1.40e5 ('Liq', 'water', '2'): -2.0901E3, ('Liq', 'water', '3'): 8.1250, ('Liq', 'water', '4'): -1.4116E-2, ('Liq', 'water', '5'): 9.3701E-6, ('Vap', 'water', '1'): 3.654E4, ('Vap', 'water', '2'): -34.802404, ('Vap', 'water', '3'): -0.1168117, ('Vap', 'water', '4'): -0.000130031, ('Vap', 'water', '5'): 5.25445E-08, ('Liq', 'CO2', '1'): -8.3043E6, # 6.6653e1, ('Liq', 'CO2', '2'): 1.0437E5, # 6.7659e3, ('Liq', 'CO2', '3'): -4.3333E2, # -1.2363e2, ('Liq', 'CO2', '4'): 6.0042E-1, # 4.7827e2, # Eqn 2 ('Liq', 'CO2', '5'): 0, ('Vap', 'CO2', '1'): 27095.326, ('Vap', 'CO2', '2'): 11.273784, ('Vap', 'CO2', '3'): 0.12487628, ('Vap', 'CO2', '4'): -0.000197374, ('Vap', 'CO2', '5'): 8.77958E-08 } self.cp_ig = Param(self.phase_list, self.component_list, ['1', '2', '3', '4', '5'], mutable=False, initialize=extract_data(cp_ig_data), doc="parameters to compute Cp_comp") # Source: NIST # fitted to Antoine form # Unit: Pvp [bar] -> unit conversion later pressure_sat_coeff_data = { ('ethanol', 'A'): 5.24677, ('ethanol', 'B'): 1598.673, ('ethanol', 'C'): -46.424, ('water', 'A'): 5.40221, ('water', 'B'): 1838.675, ('water', 'C'): -31.737, ('CO2', 'A'): 6.812, ('CO2', 'B'): 1302, ('CO2', 'C'): -3.494 } self.pressure_sat_coeff = Param( self.component_list, ['A', 'B', 'C'], mutable=False, initialize=extract_data(pressure_sat_coeff_data), doc="parameters to compute Cp_comp") # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid dh_vap = {'ethanol': 42.4e3, 'water': 43.86e3, 'CO2': 16.5e3} self.dh_vap = Param(self.component_list, mutable=False, initialize=extract_data(dh_vap), doc="heat of vaporization") @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mol': { 'method': None, 'units': 'mol/s' }, 'flow_mol_phase_comp': { 'method': None, 'units': 'mol/s' }, 'mole_frac_comp': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'flow_mol_phase': { 'method': None, 'units': 'mol/s' }, 'dens_mol_phase': { 'method': '_dens_mol_phase', 'units': 'mol/m^3' }, 'pressure_sat': { 'method': '_pressure_sat', 'units': 'Pa' }, 'mole_frac_phase_comp': { 'method': '_mole_frac_phase', 'units': 'no unit' }, 'energy_internal_mol_phase_comp': { 'method': '_energy_internal_mol_phase_comp', 'units': 'J/mol' }, 'energy_internal_mol_phase': { 'method': '_enenrgy_internal_mol_phase', 'units': 'J/mol' }, 'enth_mol_phase_comp': { 'method': '_enth_mol_phase_comp', 'units': 'J/mol' }, 'enth_mol_phase': { 'method': '_enth_mol_phase', 'units': 'J/mol' }, 'entr_mol_phase_comp': { 'method': '_entr_mol_phase_comp', 'units': 'J/mol' }, 'entr_mol_phase': { 'method': '_entr_mol_phase', 'units': 'J/mol' }, 'temperature_bubble': { 'method': '_temperature_bubble', 'units': 'K' }, 'temperature_dew': { 'method': '_temperature_dew', 'units': 'K' }, 'pressure_bubble': { 'method': '_pressure_bubble', 'units': 'Pa' }, 'pressure_dew': { 'method': '_pressure_dew', 'units': 'Pa' }, 'fug_vap': { 'method': '_fug_vap', 'units': 'Pa' }, 'fug_liq': { 'method': '_fug_liq', 'units': 'Pa' }, 'dh_vap': { 'method': '_dh_vap', 'units': 'J/mol' }, 'ds_vap': { 'method': '_ds_vap', 'units': 'J/mol.K' } }) obj.add_default_units({ 'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.g, 'amount': pyunits.mol, 'temperature': pyunits.K })
class Iapws95ParameterBlockData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "phase_presentation", ConfigValue( default=PhaseType.MIX, domain=In(PhaseType), description="Set the way phases are presented to models", doc="""Set the way phases are presented to models. The MIX option appears to the framework to be a mixed phase containing liquid and/or vapor. The mixed option can simplify calculations at the unit model level since it can be treated as a single phase, but unit models such as flash vessels will not be able to treate the phases indepedently. The LG option presents as two sperate phases to the framework. The L or G options can be used if it is known for sure that only one phase is present. **default** - PhaseType.MIX **Valid values:** { **PhaseType.MIX** - Present a mixed phase with liquid and/or vapor, **PhaseType.LG** - Present a liquid and vapor phase, **PhaseType.L** - Assume only liquid can be present, **PhaseType.G** - Assume only vapor can be present}""")) CONFIG.declare( "state_vars", ConfigValue( default=StateVars.PH, domain=In(StateVars), description="State variable set", doc= """The set of state variables to use. Depending on the use, one state variable set or another may be better computationally. Usually pressure and enthalpy are the best choice because they are well behaved during a phase change. **default** - StateVars.PH **Valid values:** { **StateVars.PH** - Pressure-Enthalpy, **StateVars.TPX** - Temperature-Pressure-Quality}""")) def build(self): super(Iapws95ParameterBlockData, self).build() self.state_block_class = Iapws95StateBlock # Location of the *.so or *.dll file for external functions self.plib = _so self.available = os.path.isfile(self.plib) # Phase list self.private_phase_list = Set(initialize=["Vap", "Liq"]) if self.config.phase_presentation == PhaseType.MIX: self.phase_list = Set(initialize=["Mix"]) elif self.config.phase_presentation == PhaseType.LG: self.phase_list = Set(initialize=["Vap", "Liq"]) elif self.config.phase_presentation == PhaseType.L: self.phase_list = Set(initialize=["Liq"]) elif self.config.phase_presentation == PhaseType.G: self.phase_list = Set(initialize=["Vap"]) # State var set self.state_vars = self.config.state_vars # Component list - a list of component identifiers self.component_list = Set(initialize=['H2O']) # List of phase equilibrium self.phase_equilibrium_idx = Set(initialize=[1]) self.phase_equilibrium_list = {1: ["H2O", ("Vap", "Liq")]} # Parameters, these should match what's in the C code self.temperature_crit = Param(initialize=647.096, doc='Critical temperature [K]') self.pressure_crit = Param(initialize=2.2064e7, doc='Critical pressure [Pa]') self.dens_mass_crit = Param(initialize=322, doc='Critical density [kg/m3]') self.gas_const = Param(initialize=8.3144598, doc='Gas Constant [J/mol/K]') self.mw = Param(initialize=0.01801528, doc='Molecular weight [kg/mol]') #Thermal conductivity parameters. # "Release on the IAPWS Formulation 2011 for the Thermal Conductivity of # Ordinary Water Substance" self.tc_L0 = Param(RangeSet(0, 5), initialize={ 0: 2.443221e-3, 1: 1.323095e-2, 2: 6.770357e-3, 3: -3.454586e-3, 4: 4.096266e-4 }, doc="0th order themalcondutivity paramters") self.tc_L1 = Param(RangeSet(0, 5), RangeSet(0, 6), initialize={ (0, 0): 1.60397357, (1, 0): 2.33771842, (2, 0): 2.19650529, (3, 0): -1.21051378, (4, 0): -2.7203370, (0, 1): -0.646013523, (1, 1): -2.78843778, (2, 1): -4.54580785, (3, 1): 1.60812989, (4, 1): 4.57586331, (0, 2): 0.111443906, (1, 2): 1.53616167, (2, 2): 3.55777244, (3, 2): -0.621178141, (4, 2): -3.18369245, (0, 3): 0.102997357, (1, 3): -0.463045512, (2, 3): -1.40944978, (3, 3): 0.0716373224, (4, 3): 1.1168348, (0, 4): -0.0504123634, (1, 4): 0.0832827019, (2, 4): 0.275418278, (3, 4): 0.0, (4, 4): -0.19268305, (0, 5): 0.00609859258, (1, 5): -0.00719201245, (2, 5): -0.0205938816, (3, 5): 0.0, (4, 5): 0.012913842 }, doc="1st order themalcondutivity paramters") #Viscosity paramters #"Release on the IAPWS Formulation 2008 for the Viscosity of # Ordinary Water Substance " self.visc_H0 = Param(RangeSet(0, 4), initialize={ 0: 1.67752, 1: 2.20462, 2: 0.6366564, 3: -0.241605 }, doc="0th order viscosity parameters") self.visc_H1 = Param(RangeSet(0, 6), RangeSet(0, 7), initialize={ (0, 0): 5.20094e-1, (1, 0): 8.50895e-2, (2, 0): -1.08374, (3, 0): -2.89555e-1, (4, 0): 0.0, (5, 0): 0.0, (0, 1): 2.22531e-1, (1, 1): 9.99115e-1, (2, 1): 1.88797, (3, 1): 1.26613, (4, 1): 0.0, (5, 1): 1.20573e-1, (0, 2): -2.81378e-1, (1, 2): -9.06851e-1, (2, 2): -7.72479e-1, (3, 2): -4.89837e-1, (4, 2): -2.57040e-1, (5, 2): 0.0, (0, 3): 1.61913e-1, (1, 3): 2.57399e-1, (2, 3): 0.0, (3, 3): 0.0, (4, 3): 0.0, (5, 3): 0.0, (0, 4): -3.25372e-2, (1, 4): 0.0, (2, 4): 0.0, (3, 4): 6.98452e-2, (4, 4): 0.0, (5, 4): 0.0, (0, 5): 0.0, (1, 5): 0.0, (2, 5): 0.0, (3, 5): 0.0, (4, 5): 8.72102e-3, (5, 5): 0.0, (0, 6): 0.0, (1, 6): 0.0, (2, 6): 0.0, (3, 6): -4.35673e-3, (4, 6): 0.0, (5, 6): -5.93264e-4 }, doc="1st order viscosity parameters") self.smoothing_pressure_over = Param( mutable=True, initialize=1e-4, doc='Smooth max parameter (pressure over)') self.smoothing_pressure_under = Param( mutable=True, initialize=1e-4, doc='Smooth max parameter (pressure under)') @classmethod def define_metadata(cls, obj): obj.add_properties({ 'temperature_crit': { 'method': None, 'units': 'K' }, 'pressure_crit': { 'method': None, 'units': 'Pa' }, 'dens_mass_crit': { 'method': None, 'units': 'kg/m^3' }, 'gas_const': { 'method': None, 'units': 'J/mol.K' }, 'mw': { 'method': None, 'units': 'kg/mol' }, 'temperature_sat': { 'method': 'None', 'units': 'K' }, 'flow_mol': { 'method': None, 'units': 'mol/s' }, 'flow_mass': { 'method': None, 'units': 'kg/s' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'vapor_frac': { 'method': None, 'units': None }, 'dens_mass_phase': { 'method': None, 'units': 'kg/m^3' }, 'temperature_red': { 'method': None, 'units': None }, 'pressure_sat': { 'method': None, 'units': 'kPa' }, 'energy_internal_mol_phase': { 'method': None, 'units': 'J/mol' }, 'enth_mol_phase': { 'method': None, 'units': 'J/mol' }, 'entr_mol_phase': { 'method': None, 'units': 'J/mol.K' }, 'cp_mol_phase': { 'method': None, 'units': 'J/mol.K' }, 'cv_mol_phase': { 'method': None, 'units': 'J/mol.K' }, 'speed_sound_phase': { 'method': None, 'units': 'm/s' }, 'dens_mol_phase': { 'method': None, 'units': 'mol/m^3' }, 'therm_cond_phase': { 'method': None, 'units': 'W/m.K' }, 'visc_d_phase': { 'method': None, 'units': 'Pa.s' }, 'visc_k_phase': { 'method': None, 'units': 'm^2/s' }, 'phase_frac': { 'method': None, 'units': None }, 'flow_mol_comp': { 'method': None, 'units': 'mol/s' }, 'energy_internal_mol': { 'method': None, 'units': 'J/mol' }, 'enth_mol': { 'method': None, 'units': 'J/mol' }, 'entr_mol': { 'method': None, 'units': 'J/mol.K' }, 'cp_mol': { 'method': None, 'units': 'J/mol.K' }, 'cv_mol': { 'method': None, 'units': 'J/mol.K' }, 'heat_capacity_ratio': { 'method': None, 'units': None }, 'dens_mass': { 'method': None, 'units': 'kg/m^3' }, 'dens_mol': { 'method': None, 'units': 'mol/m^3' }, 'dh_vap_mol': { 'method': None, 'units': 'J/mol' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'kg', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'mol' })
class NaClParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): """ Callable method for Block construction. """ super(NaClParameterData, self).build() self._state_block_class = NaClStateBlock # components self.H2O = Solvent() self.NaCl = Solute() # phases self.Liq = LiquidPhase() # reference # this package is developed from Bartholomew & Mauter (2019) https://doi.org/10.1016/j.memsci.2018.11.067 # the enthalpy calculations are from Sharqawy et al. (2010) http://dx.doi.org/10.5004/dwt.2010.1079 # molecular weight mw_comp_data = {"H2O": 18.01528e-3, "NaCl": 58.44e-3} self.mw_comp = Param( self.component_list, mutable=False, initialize=extract_data(mw_comp_data), units=pyunits.kg / pyunits.mol, doc="Molecular weight kg/mol", ) # mass density parameters, eq 4 in Bartholomew dens_mass_param_dict = {"0": 995, "1": 756} self.dens_mass_param = Var( dens_mass_param_dict.keys(), domain=Reals, initialize=dens_mass_param_dict, units=pyunits.kg / pyunits.m**3, doc="Mass density parameters", ) # dynamic viscosity parameters, eq 5 in Bartholomew visc_d_param_dict = {"0": 9.80e-4, "1": 2.15e-3} self.visc_d_param = Var( visc_d_param_dict.keys(), domain=Reals, initialize=visc_d_param_dict, units=pyunits.Pa * pyunits.s, doc="Dynamic viscosity parameters", ) # diffusivity parameters, eq 6 in Bartholomew diffus_param_dict = { "0": 1.51e-9, "1": -2.00e-9, "2": 3.01e-8, "3": -1.22e-7, "4": 1.53e-7, } self.diffus_param = Var( diffus_param_dict.keys(), domain=Reals, initialize=diffus_param_dict, units=pyunits.m**2 / pyunits.s, doc="Dynamic viscosity parameters", ) # osmotic coefficient parameters, eq. 3b in Bartholomew osm_coeff_param_dict = {"0": 0.918, "1": 8.89e-2, "2": 4.92} self.osm_coeff_param = Var( osm_coeff_param_dict.keys(), domain=Reals, initialize=osm_coeff_param_dict, units=pyunits.dimensionless, doc="Osmotic coefficient parameters", ) # TODO: update for NaCl solution, relationship from Sharqawy is for seawater # specific enthalpy parameters, eq. 55 and 43 in Sharqawy (2010) self.enth_mass_param_A1 = Var( within=Reals, initialize=124.790, units=pyunits.J / pyunits.kg, doc="Specific enthalpy parameter A1", ) self.enth_mass_param_A2 = Var( within=Reals, initialize=4203.075, units=(pyunits.J / pyunits.kg) * pyunits.K**-1, doc="Specific enthalpy parameter A2", ) self.enth_mass_param_A3 = Var( within=Reals, initialize=-0.552, units=(pyunits.J / pyunits.kg) * pyunits.K**-2, doc="Specific enthalpy parameter A3", ) self.enth_mass_param_A4 = Var( within=Reals, initialize=0.004, units=(pyunits.J / pyunits.kg) * pyunits.K**-3, doc="Specific enthalpy parameter A4", ) self.enth_mass_param_B1 = Var( within=Reals, initialize=27062.623, units=pyunits.dimensionless, doc="Specific enthalpy parameter B1", ) self.enth_mass_param_B2 = Var( within=Reals, initialize=4835.675, units=pyunits.dimensionless, doc="Specific enthalpy parameter B2", ) # traditional parameters are the only Vars currently on the block and should be fixed for v in self.component_objects(Var): v.fix() # ---default scaling--- self.set_default_scaling("temperature", 1e-2) self.set_default_scaling("pressure", 1e-6) self.set_default_scaling("dens_mass_phase", 1e-3, index="Liq") self.set_default_scaling("visc_d_phase", 1e3, index="Liq") self.set_default_scaling("diffus_phase", 1e9, index="Liq") self.set_default_scaling("osm_coeff", 1e0) self.set_default_scaling("enth_mass_phase", 1e-4, index="Liq") @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties( { "flow_mass_phase_comp": {"method": None}, "temperature": {"method": None}, "pressure": {"method": None}, "mass_frac_phase_comp": {"method": "_mass_frac_phase_comp"}, "dens_mass_phase": {"method": "_dens_mass_phase"}, "flow_vol_phase": {"method": "_flow_vol_phase"}, "flow_vol": {"method": "_flow_vol"}, "conc_mass_phase_comp": {"method": "_conc_mass_phase_comp"}, "flow_mol_phase_comp": {"method": "_flow_mol_phase_comp"}, "mole_frac_phase_comp": {"method": "_mole_frac_phase_comp"}, "molality_comp": {"method": "_molality_comp"}, "diffus_phase": {"method": "_diffus_phase"}, "visc_d_phase": {"method": "_visc_d_phase"}, "osm_coeff": {"method": "_osm_coeff"}, "pressure_osm": {"method": "_pressure_osm"}, "enth_mass_phase": {"method": "_enth_mass_phase"}, "enth_flow": {"method": "_enth_flow"}, } ) obj.add_default_units( { "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, } )
class PhysicalParameterData(PhysicalParameterBlock): """ Property Parameter Block Class. """ # Config block for the _IdealStateBlock CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare("valid_phase", ConfigValue( default=('Vap', 'Liq'), domain=In(['Liq', 'Vap', ('Vap', 'Liq'), ('Liq', 'Vap')]), description="Flag indicating the valid phase", doc="""Flag indicating the valid phase for a given set of conditions, and thus corresponding constraints should be included, **default** - ('Vap', 'Liq'). **Valid values:** { **'Liq'** - Liquid only, **'Vap'** - Vapor only, **('Vap', 'Liq')** - Vapor-liquid equilibrium, **('Liq', 'Vap')** - Vapor-liquid equilibrium,}""")) CONFIG.declare("Cp", ConfigValue( default=0.035, domain=float, description="Constant pressure heat capacity in MJ/(kmol K)", doc="""Value for the constant pressure heat capacity, **default** = 0.035 MJ/(kmol K)""")) def build(self): ''' Callable method for Block construction. ''' super(PhysicalParameterData, self).build() self._state_block_class = IdealStateBlock # List of valid phases and components in property package if self.config.valid_phase == ('Liq', 'Vap') or \ self.config.valid_phase == ('Vap', 'Liq'): self.Liq = LiquidPhase() self.Vap = VaporPhase() elif self.config.valid_phase == 'Liq': self.Liq = LiquidPhase() else: self.Vap = VaporPhase() self.CH4 = Component() self.CO = Component() self.H2 = Component() self.CH3OH = Component() self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4]) self.phase_equilibrium_list = \ {1: ["CH4", ("Vap", "Liq")], 2: ["CO", ("Vap", "Liq")], 3: ["H2", ("Vap", "Liq")], 4: ["CH3OH", ("Vap", "Liq")]} # Antoine coefficients assume pressure in mmHG and temperature in K self.vapor_pressure_coeff = {('CH4', 'A'): 15.2243, ('CH4', 'B'): 897.84, ('CH4', 'C'): -7.16, ('CO', 'A'): 14.3686, ('CO', 'B'): 530.22, ('CO', 'C'): -13.15, ('H2', 'A'): 13.6333, ('H2', 'B'): 164.9, ('H2', 'C'): 3.19, ('CH3OH', 'A'): 18.5875, ('CH3OH', 'B'): 3626.55, ('CH3OH', 'C'): -34.29} Cp = self.config.Cp Cv = value(Cp - pyunits.convert(Constants.gas_constant, pyunits.MJ/pyunits.kmol/pyunits.K)) gamma = Cp / Cv self.gamma = Param(within=NonNegativeReals, mutable=True, default=gamma, doc='Ratio of Cp to Cv') self.Cp = Param(within=NonNegativeReals, mutable=True, default=Cp, units=pyunits.MJ/pyunits.kmol/pyunits.K, doc='Constant pressure heat capacity') @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties( {'flow_mol': {'method': None}, 'mole_frac': {'method': None}, 'temperature': {'method': None}, 'pressure': {'method': None}, 'flow_mol_phase': {'method': None}, 'density_mol': {'method': '_density_mol'}, 'vapor_pressure': {'method': '_vapor_pressure'}, 'mole_frac_phase': {'method': '_mole_frac_phase'}, 'enthalpy_comp_liq': {'method': '_enthalpy_comp_liq'}, 'enthalpy_comp_vap': {'method': '_enthalpy_comp_vap'}, 'enthalpy_liq': {'method': '_enthalpy_liq'}, 'enthalpy_vap': {'method': '_enthalpy_vap'}}) obj.add_default_units({'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.Gg, # yields base units MJ, MPa 'amount': pyunits.kmol, 'temperature': pyunits.hK})
class MethaneParameterData(ActivityCoeffParameterData): # Methane combstion only considers and ideal vapor phase, so need to # overload the user-selection of activity coefficient model and valid # phases. Do this by creating our own Config block with limited choices. CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "activity_coeff_model", ConfigValue(default="Ideal", domain=In(["Ideal"]), description="Methane combustion supports ideal gas only")) CONFIG.declare( "state_vars", ConfigValue( default="FTPz", domain=In(["FTPz", "FcTP"]), description="Flag indicating the choice for state variables", doc="""Flag indicating the choice for state variables to be used for the state block, and thus corresponding constraints should be included, **default** - FTPz **Valid values:** { **"FTPx"** - Total flow, Temperature, Pressure and Mole fraction, **"FcTP"** - Component flow, Temperature and Pressure}""")) CONFIG.declare( "valid_phase", ConfigValue(default="Vap", domain=In(["Vap"]), description="Methane combustion supports ideal gas only")) def build(self): ''' Callable method for Block construction. ''' super(MethaneParameterData, self).build() # Component list - a list of component identifiers self.H2 = Component() self.N2 = Component() self.O2 = Component() self.CH4 = Component() self.CO = Component() self.CO2 = Component() self.H2O = Component() self.NH3 = Component() # List of all chemical elements that constitute the chemical species self.element_list = Set(initialize=['H', 'N', 'O', 'C']) # Elemental composition of all species self.element_comp = { 'H2': { 'H': 2, 'N': 0, 'O': 0, 'C': 0 }, 'N2': { 'H': 0, 'N': 2, 'O': 0, 'C': 0 }, 'O2': { 'H': 0, 'N': 0, 'O': 2, 'C': 0 }, 'CH4': { 'H': 4, 'N': 0, 'O': 0, 'C': 1 }, 'CO': { 'H': 0, 'N': 0, 'O': 1, 'C': 1 }, 'CO2': { 'H': 0, 'N': 0, 'O': 2, 'C': 1 }, 'H2O': { 'H': 2, 'N': 0, 'O': 1, 'C': 0 }, 'NH3': { 'H': 3, 'N': 1, 'O': 0, 'C': 0 } } # Thermodynamic reference state self.pressure_reference = Param(mutable=True, default=101325, doc='Reference pressure [Pa]', units=pyunits.Pa) self.temperature_reference = Param(mutable=True, default=1500, doc='Reference temperature [K]', units=pyunits.K) # Constants for specific heat capacity, enthalpy # Sources: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid Cp_Vap_A_data = { ('CH4'): 1.925e1, ('CO'): 3.087e1, ('CO2'): 1.980e1, ('H2'): 2.714e1, ('H2O'): 3.224e1, ('N2'): 3.115e1, ('NH3'): 2.731e1, ('O2'): 2.811e1 } Cp_Vap_B_data = { ('CH4'): 5.213e-2, ('CO'): -1.285e-2, ('CO2'): 7.344e-2, ('H2'): 9.274e-3, ('H2O'): 1.924e-3, ('N2'): -1.357e-2, ('NH3'): 2.383e-2, ('O2'): -3.680e-6 } Cp_Vap_C_data = { ('CH4'): 1.197e-5, ('CO'): 2.789e-5, ('CO2'): -5.602e-5, ('H2'): -1.381e-5, ('H2O'): 1.055e-5, ('N2'): 2.680e-5, ('NH3'): 1.707e-5, ('O2'): 1.746e-5 } Cp_Vap_D_data = { ('CH4'): -1.132e-8, ('CO'): -1.272e-8, ('CO2'): 1.715e-8, ('H2'): 7.645e-9, ('H2O'): -3.596e-9, ('N2'): -1.168e-8, ('NH3'): -1.185e-8, ('O2'): -1.065e-8 } Cp_Vap_E_data = { ('CH4'): 0, ('CO'): 0, ('CO2'): 0, ('H2'): 0, ('H2O'): 0, ('N2'): 0, ('NH3'): 0, ('O2'): 0 } self.cp_mol_vap_comp_coeff_A = Param( self.component_list, units=pyunits.J / pyunits.mol / pyunits.K, doc="Vapor phase Cp parameter A", initialize=extract_data(Cp_Vap_A_data)) self.cp_mol_vap_comp_coeff_B = Param( self.component_list, units=pyunits.J / pyunits.mol / pyunits.K**2, doc="Vapor phase Cp parameter B", initialize=extract_data(Cp_Vap_B_data)) self.cp_mol_vap_comp_coeff_C = Param( self.component_list, units=pyunits.J / pyunits.mol / pyunits.K**3, doc="Vapor phase Cp parameter C", initialize=extract_data(Cp_Vap_C_data)) self.cp_mol_vap_comp_coeff_D = Param( self.component_list, units=pyunits.J / pyunits.mol / pyunits.K**4, doc="Vapor phase Cp parameter D", initialize=extract_data(Cp_Vap_D_data)) self.cp_mol_vap_comp_coeff_E = Param( self.component_list, units=pyunits.J / pyunits.mol / pyunits.K**5, doc="Vapor phase Cp parameter E", initialize=extract_data(Cp_Vap_E_data)) # Source: NIST Webbook, 9th October 2019 dh_form = { ("Vap", "CH4"): -74600, ("Vap", "CO"): -110530, ("Vap", "CO2"): -393520, ("Vap", "H2"): 0, ("Vap", "H2O"): -241830, ("Vap", "N2"): 0, ("Vap", "NH3"): -45900, ("Vap", "O2"): 0 } self.dh_form = Param(self.phase_list, self.component_list, mutable=False, initialize=extract_data(dh_form), doc="Heats of formation (J/mol)", units=pyunits.J / pyunits.mol) # Source: NIST Webbook, 9th October 2019 ds_form = { ("Vap", "CH4"): 186.25, ("Vap", "CO"): 197.66, ("Vap", "CO2"): 213.79, ("Vap", "H2"): 130.68, ("Vap", "H2O"): 188.84, ("Vap", "N2"): 191.61, ("Vap", "NH3"): 192.77, ("Vap", "O2"): 205.15 } self.ds_form = Param(self.phase_list, self.component_list, mutable=False, initialize=extract_data(ds_form), doc="Entropies of formation (J/mol.K)", units=pyunits.J / pyunits.mol / pyunits.K)
class FlueGasParameterData(PhysicalParameterBlock): """ Property Parameter Block Class Contains parameters and indexing sets associated with properties for flue gas. The ideal gas assumption is applied. """ CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "components", ConfigValue( default=["N2", "O2", "NO", "CO2", "H2O", "SO2"], domain=list, description="Components to include", ), ) def build(self): """Add contents to the block.""" super().build() self._state_block_class = FlueGasStateBlock _valid_comps = ["N2", "O2", "NO", "CO2", "H2O", "SO2"] for j in self.config.components: if j not in _valid_comps: raise ConfigurationError(f"Component '{j}' is not supported") self.add_component(j, Component()) # Create Phase object self.Vap = VaporPhase() # Molecular weight self.mw_comp = Param( self.component_list, initialize={ k: v for k, v in { "O2": 0.0319988, "N2": 0.0280134, "NO": 0.0300061, "CO2": 0.0440095, "H2O": 0.0180153, "SO2": 0.064064, }.items() if k in self.component_list }, doc="Molecular Weight [kg/mol]", units=pyunits.kg / pyunits.mol, ) # Thermodynamic reference state self.pressure_ref = Param( within=PositiveReals, default=1.01325e5, doc="Reference pressure [Pa]", units=pyunits.Pa, ) self.temperature_ref = Param( within=PositiveReals, default=298.15, doc="Reference temperature [K]", units=pyunits.K, ) # Critical Properties self.pressure_crit = Param( self.component_list, within=PositiveReals, initialize={ k: v for k, v in { "O2": 50.45985e5, "N2": 33.943875e5, "NO": 64.85e5, "CO2": 73.8e5, "H2O": 220.64e5, "SO2": 7.883e6, }.items() if k in self.component_list }, doc="Critical pressure [Pa]", units=pyunits.Pa, ) self.temperature_crit = Param( self.component_list, within=PositiveReals, initialize={ k: v for k, v in { "O2": 154.58, "N2": 126.19, "NO": 180.0, "CO2": 304.18, "H2O": 647, "SO2": 430.8, }.items() if k in self.component_list }, doc="Critical temperature [K]", units=pyunits.K, ) # Constants for specific heat capacity, enthalpy, and entropy # calculations for ideal gas (from NIST 01/08/2020 # https://webbook.nist.gov/cgi/cbook.cgi?ID=C7727379&Units=SI&Mask=1#Thermo-Gas) cp_mol_ig_comp_coeff_parameter_A = { k: v for k, v in { "N2": 19.50583, "O2": 30.03235, "CO2": 24.99735, "H2O": 30.092, "NO": 23.83491, "SO2": 21.43049, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_B = { k: v for k, v in { "N2": 19.88705, "O2": 8.772972, "CO2": 55.18696, "H2O": 6.832514, "NO": 12.58878, "SO2": 74.35094, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_C = { k: v for k, v in { "N2": -8.598535, "O2": -3.98813, "CO2": -33.69137, "H2O": 6.793435, "NO": -1.139011, "SO2": -57.75217, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_D = { k: v for k, v in { "N2": 1.369784, "O2": 0.788313, "CO2": 7.948387, "H2O": -2.53448, "NO": -1.497459, "SO2": 16.35534, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_E = { k: v for k, v in { "N2": 0.527601, "O2": -0.7416, "CO2": -0.136638, "H2O": 0.082139, "NO": 0.214194, "SO2": 0.086731, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_F = { k: v for k, v in { "N2": -4.935202, "O2": -11.3247, "CO2": -403.6075, "H2O": -250.881, "NO": 83.35783, "SO2": -305.7688, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_G = { k: v for k, v in { "N2": 212.39, "O2": 236.1663, "CO2": 228.2431, "H2O": 223.3967, "NO": 237.1219, "SO2": 254.8872, }.items() if k in self.component_list } cp_mol_ig_comp_coeff_parameter_H = { k: v for k, v in { "N2": 0, "O2": 0, "CO2": -393.5224, "H2O": -241.8264, "NO": 90.29114, "SO2": -296.8422, }.items() if k in self.component_list } self.cp_mol_ig_comp_coeff_A = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_A, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K, ) self.cp_mol_ig_comp_coeff_B = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_B, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK, ) self.cp_mol_ig_comp_coeff_C = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_C, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK**2, ) self.cp_mol_ig_comp_coeff_D = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_D, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K / pyunits.kK**3, ) self.cp_mol_ig_comp_coeff_E = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_E, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K * pyunits.kK**2, ) self.cp_mol_ig_comp_coeff_F = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_F, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.kJ / pyunits.mol, ) self.cp_mol_ig_comp_coeff_G = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_G, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.J / pyunits.mol / pyunits.K, ) self.cp_mol_ig_comp_coeff_H = Param( self.component_list, initialize=cp_mol_ig_comp_coeff_parameter_H, doc="Constants for spec. heat capacity for ideal gas", units=pyunits.kJ / pyunits.mol, ) # Viscosity and thermal conductivity parameters self.ce_param = Param( initialize=2.6693e-5, units=(pyunits.g**0.5 * pyunits.mol**0.5 * pyunits.angstrom**2 * pyunits.K**-0.5 * pyunits.cm**-1 * pyunits.s**-1), doc="Parameter for the Chapman-Enskog viscosity correlation", ) self.sigma = Param( self.component_list, initialize={ k: v for k, v in { "O2": 3.458, "N2": 3.621, "NO": 3.47, "CO2": 3.763, "H2O": 2.605, "SO2": 4.29, }.items() if k in self.component_list }, doc="collision diameter", units=pyunits.angstrom, ) self.ep_Kappa = Param( self.component_list, initialize={ k: v for k, v in { "O2": 107.4, "N2": 97.53, "NO": 119.0, "CO2": 244.0, "H2O": 572.4, "SO2": 252.0, }.items() if k in self.component_list }, doc= "Boltzmann constant divided by characteristic Lennard-Jones energy", units=pyunits.K, ) self.set_default_scaling("flow_mol", 1e-4) self.set_default_scaling("flow_mass", 1e-3) self.set_default_scaling("flow_vol", 1e-3) # anything not explicitly listed self.set_default_scaling("mole_frac_comp", 1) self.set_default_scaling("mole_frac_comp", 1e3, index="NO") self.set_default_scaling("mole_frac_comp", 1e3, index="SO2") self.set_default_scaling("mole_frac_comp", 1e2, index="H2O") self.set_default_scaling("mole_frac_comp", 1e2, index="CO2") self.set_default_scaling("flow_vol", 1) # For flow_mol_comp, will calculate from flow_mol and mole_frac_comp # user should set a scale for both, and for each compoent of # mole_frac_comp self.set_default_scaling("pressure", 1e-5) self.set_default_scaling("temperature", 1e-1) self.set_default_scaling("pressure_red", 1e-3) self.set_default_scaling("temperature_red", 1) self.set_default_scaling("enth_mol_phase", 1e-3) self.set_default_scaling("enth_mol", 1e-3) self.set_default_scaling("entr_mol", 1e-2) self.set_default_scaling("entr_mol_phase", 1e-2) self.set_default_scaling("cp_mol", 0.1) self.set_default_scaling("cp_mol_phase", 0.1) self.set_default_scaling("compress_fact", 1) self.set_default_scaling("dens_mol_phase", 1) self.set_default_scaling("pressure_sat", 1e-4) self.set_default_scaling("visc_d_comp", 1e4) self.set_default_scaling("therm_cond_comp", 1e2) self.set_default_scaling("visc_d", 1e4) self.set_default_scaling("therm_cond", 1e2) self.set_default_scaling("mw", 1) self.set_default_scaling("mw_comp", 1) @classmethod def define_metadata(cls, obj): obj.add_properties({ "flow_mol_comp": { "method": None, "units": "mol/s" }, "pressure": { "method": None, "units": "Pa" }, "temperature": { "method": None, "units": "K" }, "pressure_crit": { "method": None, "units": "Pa" }, "temperature_crit": { "method": None, "units": "K" }, "pressure_red": { "method": None, "units": None }, "temperature_red": { "method": None, "units": None }, "enth_mol_phase": { "method": "_enthalpy_calc", "units": "J/mol" }, "entr_mol_phase": { "method": "_entropy_calc", "units": "J/mol/K" }, "enth_mol": { "method": "_enthalpy_calc", "units": "J/mol" }, "entr_mol": { "method": "_entropy_calc", "units": "J/mol.K" }, "cp_mol": { "method": "_heat_cap_calc", "units": "J/mol.K" }, "cp_mol_phase": { "method": "_heat_cap_calc", "units": "J/mol/K" }, "compress_fact": { "method": "_compress_fact", "units": None }, "dens_mol_phase": { "method": "_dens_mol_phase", "units": "mol/m^3" }, "pressure_sat": { "method": "_vapor_pressure", "units": "Pa" }, "flow_vol": { "method": "_flow_volume", "units": "m^3/s" }, "visc_d": { "method": "_therm_cond", "units": "kg/m-s" }, "therm_cond": { "method": "_therm_cond", "units": "W/m-K" }, "mw_comp": { "method": None, "units": "kg/mol" }, "mw": { "method": None, "units": "kg/mol" }, }) obj.add_default_units({ "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, })
class HDAParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def _get_param(self, name: str): """Helper method to convert data stored in a DMF resource into a Pyomo rule. The intermediate form, :class:`TidyUnitData`, is constructed from the data stored in the JSON of the DMF resource. Args: name: Primary alias of DMF resource with stored data. Returns: function for `initialize` keyword of `Param` class constructor. Raises: KeyError: Resource not found ValueError: Data in resource is missing or malformed Side-effects: For future reference, the resource itself is stored in an instance dict called `self._property_data` where the keys are the parameter names and the values are instances of :class:`idaes.dmf.resource.Resource`. """ r = _dmf.find_one(name=name) if not hasattr(r, "data"): raise KeyError(f"No resource named {name} was found") try: dframe = TidyUnitData(r.data) except ValueError as err: raise ValueError(f"While extracting data for {name}: {err}") self._property_resources[name] = r return extract_data(dframe.param_data) def get_property_resource(self, name: str) -> Resource: return self._property_resources[name] def build(self): """ Callable method for Block construction. """ super(HDAParameterData, self).build() self._property_resources = { } # see _get_param(), get_property_resource() self.state_block_class = IdealStateBlock self.component_list = Set( initialize=["benzene", "toluene", "hydrogen", "methane"]) self.phase_list = Set(initialize=["Liq", "Vap"], ordered=True) # List of components in each phase (optional) self.phase_comp = { "Liq": self.component_list, "Vap": self.component_list } # List of phase equilibrium index self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4, 5]) self.phase_equilibrium_list = { 1: ["benzene", ("Vap", "Liq")], 2: ["toluene", ("Vap", "Liq")], 3: ["hydrogen", ("Vap", "Liq")], 4: ["methane", ("Vap", "Liq")], 5: ["diphenyl", ("Vap", "Liq")], } # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, doc="Reference pressure [Pa]") self.temperature_ref = Param(mutable=True, default=298.15, doc="Reference temperature [K]") self.pressure_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=self._get_param("pressure_crit"), doc="Critical pressure [Pa]", ) self.temperature_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=self._get_param("temperature_crit"), doc="Critical temperature [K]", ) # Gas Constant self.gas_const = Param( within=NonNegativeReals, mutable=False, default=8.314, doc="Gas Constant [J/mol.K]", ) self.mw_comp = Param( self.component_list, mutable=False, initialize=self._get_param("mw"), doc="molecular weight Kg/mol", ) self.dens_liq_params = Param( self.component_list, ["1", "2", "3", "4"], mutable=False, initialize=self._get_param("cp_liq"), doc="Parameters to compute liquid densities", ) self.temperature_boil = Param( self.component_list, mutable=False, initialize=self._get_param("bp"), doc="Pure component boiling points at standard pressure [K]", ) self.cp_ig = Param( self.phase_list, self.component_list, ["1", "2", "3", "4", "5"], mutable=False, initialize=self._get_param("cp_ig"), doc="parameters to compute Cp_comp", ) self.pressure_sat_coeff = Param( self.component_list, ["A", "B", "C"], mutable=False, initialize=self._get_param("pressure_sat_coeff"), doc="parameters to compute Cp_comp", ) self.dh_vap = Param( self.component_list, mutable=False, initialize=self._get_param("dh_vap"), doc="heat of vaporization", ) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ "flow_mol": { "method": None, "units": "mol/s" }, "flow_mol_phase_comp": { "method": None, "units": "mol/s" }, "mole_frac": { "method": None, "units": "none" }, "temperature": { "method": None, "units": "K" }, "pressure": { "method": None, "units": "Pa" }, "flow_mol_phase": { "method": None, "units": "mol/s" }, "dens_mol_phase": { "method": "_dens_mol_phase", "units": "mol/m^3" }, "pressure_sat": { "method": "_pressure_sat", "units": "Pa" }, "mole_frac_phase": { "method": "_mole_frac_phase", "units": "no unit" }, "enth_mol_phase_comp": { "method": "_enth_mol_phase_comp", "units": "J/mol", }, "enth_mol_phase": { "method": "_enth_mol_phase", "units": "J/mol" }, "entr_mol_phase_comp": { "method": "_entr_mol_phase_comp", "units": "J/mol", }, "entr_mol_phase": { "method": "_entr_mol_phase", "units": "J/mol" }, "temperature_bubble": { "method": "_temperature_bubble", "units": "K" }, "temperature_dew": { "method": "_temperature_dew", "units": "K" }, "pressure_bubble": { "method": "_pressure_bubble", "units": "Pa" }, "pressure_dew": { "method": "_pressure_dew", "units": "Pa" }, "fug_vap": { "method": "_fug_vap", "units": "Pa" }, "fug_liq": { "method": "_fug_liq", "units": "Pa" }, "dh_vap": { "method": "_dh_vap", "units": "J/mol" }, "ds_vap": { "method": "_ds_vap", "units": "J/mol.K" }, }) obj.add_default_units({ "time": "s", "length": "m", "mass": "g", "amount": "mol", "temperature": "K", "energy": "J", "holdup": "mol", })
class WaterParameterData(PhysicalParameterBlock): """Parameter block for a water property package.""" CONFIG = PhysicalParameterBlock.CONFIG() def build(self): """ Callable method for Block construction. """ super(WaterParameterData, self).build() self._state_block_class = WaterStateBlock # components self.H2O = Component() # phases self.Liq = LiquidPhase() self.Vap = VaporPhase() """ References This package was developed from the following references: - K.G.Nayar, M.H.Sharqawy, L.D.Banchik, and J.H.Lienhard V, "Thermophysical properties of seawater: A review and new correlations that include pressure dependence,"Desalination, Vol.390, pp.1 - 24, 2016. doi: 10.1016/j.desal.2016.02.024(preprint) - Mostafa H.Sharqawy, John H.Lienhard V, and Syed M.Zubair, "Thermophysical properties of seawater: A review of existing correlations and data,"Desalination and Water Treatment, Vol.16, pp.354 - 380, April 2010. (2017 corrections provided at http://web.mit.edu/seawater) """ # Parameters # molecular weight self.mw_comp = Param( self.component_list, mutable=False, initialize=18.01528e-3, units=pyunits.kg / pyunits.mol, doc="Molecular weight", ) # Liq mass density parameters, eq. 8 in Sharqawy et al. (2010) dens_units = pyunits.kg / pyunits.m**3 t_inv_units = pyunits.K**-1 s_inv_units = pyunits.kg / pyunits.g self.dens_mass_param_A1 = Var( within=Reals, initialize=9.999e2, units=dens_units, doc="Mass density parameter A1", ) self.dens_mass_param_A2 = Var( within=Reals, initialize=2.034e-2, units=dens_units * t_inv_units, doc="Mass density parameter A2", ) self.dens_mass_param_A3 = Var( within=Reals, initialize=-6.162e-3, units=dens_units * t_inv_units**2, doc="Mass density parameter A3", ) self.dens_mass_param_A4 = Var( within=Reals, initialize=2.261e-5, units=dens_units * t_inv_units**3, doc="Mass density parameter A4", ) self.dens_mass_param_A5 = Var( within=Reals, initialize=-4.657e-8, units=dens_units * t_inv_units**4, doc="Mass density parameter A5", ) # Vap mass density parameters (approximating using ideal gas) self.dens_mass_param_mw = Var( within=Reals, initialize=18.01528e-3, units=pyunits.kg / pyunits.mol, doc="Mass density parameter molecular weight", ) self.dens_mass_param_R = Var( within=Reals, initialize=8.31462618, units=pyunits.J / pyunits.mol / pyunits.K, doc="Mass density parameter universal gas constant", ) # vapor pressure parameters, eq. 5 and 6 in Nayar et al.(2016) self.pressure_sat_param_psatw_A1 = Var( within=Reals, initialize=-5.8002206e3, units=pyunits.K, doc="Vapor pressure of pure water parameter A1", ) self.pressure_sat_param_psatw_A2 = Var( within=Reals, initialize=1.3914993, units=pyunits.dimensionless, doc="Vapor pressure of pure water parameter A2", ) self.pressure_sat_param_psatw_A3 = Var( within=Reals, initialize=-4.8640239e-2, units=t_inv_units, doc="Vapor pressure of pure water parameter A3", ) self.pressure_sat_param_psatw_A4 = Var( within=Reals, initialize=4.1764768e-5, units=t_inv_units**2, doc="Vapor pressure of pure water parameter A4", ) self.pressure_sat_param_psatw_A5 = Var( within=Reals, initialize=-1.4452093e-8, units=t_inv_units**3, doc="Vapor pressure of pure water parameter A5", ) self.pressure_sat_param_psatw_A6 = Var( within=Reals, initialize=6.5459673, units=pyunits.dimensionless, doc="Vapor pressure of pure water parameter A6", ) # specific enthalpy parameters, eq. 55 and 43 in Sharqawy et al. (2010) enth_mass_units = pyunits.J / pyunits.kg self.enth_mass_param_A1 = Var( within=Reals, initialize=141.355, units=enth_mass_units, doc="Specific enthalpy parameter A1", ) self.enth_mass_param_A2 = Var( within=Reals, initialize=4202.07, units=enth_mass_units * t_inv_units, doc="Specific enthalpy parameter A2", ) self.enth_mass_param_A3 = Var( within=Reals, initialize=-0.535, units=enth_mass_units * t_inv_units**2, doc="Specific enthalpy parameter A3", ) self.enth_mass_param_A4 = Var( within=Reals, initialize=0.004, units=enth_mass_units * t_inv_units**3, doc="Specific enthalpy parameter A4", ) # self.enth_mass_param_B1 = Var( # within=Reals, initialize=-2.348e4, units=enth_mass_units, # doc='Specific enthalpy parameter B1') # self.enth_mass_param_B2 = Var( # within=Reals, initialize=3.152e5, units=enth_mass_units, # doc='Specific enthalpy parameter B2') # self.enth_mass_param_B3 = Var( # within=Reals, initialize=2.803e6, units=enth_mass_units, # doc='Specific enthalpy parameter B3') # self.enth_mass_param_B4 = Var( # within=Reals, initialize=-1.446e7, units=enth_mass_units, # doc='Specific enthalpy parameter B4') # self.enth_mass_param_B5 = Var( # within=Reals, initialize=7.826e3, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B5') # self.enth_mass_param_B6 = Var( # within=Reals, initialize=-4.417e1, units=enth_mass_units * t_inv_units**2, # doc='Specific enthalpy parameter B6') # self.enth_mass_param_B7 = Var( # within=Reals, initialize=2.139e-1, units=enth_mass_units * t_inv_units**3, # doc='Specific enthalpy parameter B7') # self.enth_mass_param_B8 = Var( # within=Reals, initialize=-1.991e4, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B8') # self.enth_mass_param_B9 = Var( # within=Reals, initialize=2.778e4, units=enth_mass_units * t_inv_units, # doc='Specific enthalpy parameter B9') # self.enth_mass_param_B10 = Var( # within=Reals, initialize=9.728e1, units=enth_mass_units * t_inv_units**2, # doc='Specific enthalpy parameter B10') # specific heat parameters from eq (9) in Sharqawy et al. (2010) cp_units = pyunits.J / (pyunits.kg * pyunits.K) self.cp_phase_param_A1 = Var( within=Reals, initialize=5.328, units=cp_units, doc="Specific heat of seawater parameter A1", ) # self.cp_phase_param_A2 = Var( # within=Reals, initialize=-9.76e-2, units=cp_units * s_inv_units, # doc='Specific heat of seawater parameter A2') # self.cp_phase_param_A3 = Var( # within=Reals, initialize=4.04e-4, units=cp_units * s_inv_units**2, # doc='Specific heat of seawater parameter A3') self.cp_phase_param_B1 = Var( within=Reals, initialize=-6.913e-3, units=cp_units * t_inv_units, doc="Specific heat of seawater parameter B1", ) # self.cp_phase_param_B2 = Var( # within=Reals, initialize=7.351e-4, units=cp_units * s_inv_units * t_inv_units, # doc='Specific heat of seawater parameter B2') # self.cp_phase_param_B3 = Var( # within=Reals, initialize=-3.15e-6, units=cp_units * s_inv_units**2 * t_inv_units, # doc='Specific heat of seawater parameter B3') self.cp_phase_param_C1 = Var( within=Reals, initialize=9.6e-6, units=cp_units * t_inv_units**2, doc="Specific heat of seawater parameter C1", ) # self.cp_phase_param_C2 = Var( # within=Reals, initialize=-1.927e-6, units=cp_units * s_inv_units * t_inv_units**2, # doc='Specific heat of seawater parameter C2') # self.cp_phase_param_C3 = Var( # within=Reals, initialize=8.23e-9, units=cp_units * s_inv_units**2 * t_inv_units**2, # doc='Specific heat of seawater parameter C3') self.cp_phase_param_D1 = Var( within=Reals, initialize=2.5e-9, units=cp_units * t_inv_units**3, doc="Specific heat of seawater parameter D1", ) # self.cp_phase_param_D2 = Var( # within=Reals, initialize=1.666e-9, units=cp_units * s_inv_units * t_inv_units**3, # doc='Specific heat of seawater parameter D2') # self.cp_phase_param_D3 = Var( # within=Reals, initialize=-7.125e-12, units=cp_units * s_inv_units**2 * t_inv_units**3, # doc='Specific heat of seawater parameter D3') # Specific heat parameters for Cp vapor from NIST Webbook # Chase, M.W., Jr., NIST-JANAF Themochemical Tables, Fourth Edition, J. Phys. Chem. Ref. Data, Monograph 9, 1998, 1-1951 self.cp_vap_param_A = Var( within=Reals, initialize=30.09200 / 18.01528e-3, units=cp_units, doc="Specific heat of water vapor parameter A", ) self.cp_vap_param_B = Var( within=Reals, initialize=6.832514 / 18.01528e-3, units=cp_units * t_inv_units, doc="Specific heat of water vapor parameter B", ) self.cp_vap_param_C = Var( within=Reals, initialize=6.793435 / 18.01528e-3, units=cp_units * t_inv_units**2, doc="Specific heat of water vapor parameter C", ) self.cp_vap_param_D = Var( within=Reals, initialize=-2.534480 / 18.01528e-3, units=cp_units * t_inv_units**3, doc="Specific heat of water vapor parameter D", ) self.cp_vap_param_E = Var( within=Reals, initialize=0.082139 / 18.01528e-3, units=cp_units * t_inv_units**-2, doc="Specific heat of water vapor parameter E", ) # latent heat of pure water parameters from eq. 54 in Sharqawy et al. (2010) self.dh_vap_w_param_0 = Var( within=Reals, initialize=2.501e6, units=enth_mass_units, doc="Latent heat of pure water parameter 0", ) self.dh_vap_w_param_1 = Var( within=Reals, initialize=-2.369e3, units=cp_units, doc="Latent heat of pure water parameter 1", ) self.dh_vap_w_param_2 = Var( within=Reals, initialize=2.678e-1, units=enth_mass_units * t_inv_units**2, doc="Latent heat of pure water parameter 2", ) self.dh_vap_w_param_3 = Var( within=Reals, initialize=-8.103e-3, units=enth_mass_units * t_inv_units**3, doc="Latent heat of pure water parameter 3", ) self.dh_vap_w_param_4 = Var( within=Reals, initialize=-2.079e-5, units=enth_mass_units * t_inv_units**4, doc="Latent heat of pure water parameter 4", ) # traditional parameters are the only Vars currently on the block and should be fixed for v in self.component_objects(Var): v.fix() # ---default scaling--- self.set_default_scaling("temperature", 1e-2) self.set_default_scaling("pressure", 1e-5) self.set_default_scaling("dens_mass_phase", 1e-3, index="Liq") self.set_default_scaling("dens_mass_phase", 1, index="Vap") # self.set_default_scaling('dens_mass_solvent', 1e-3) self.set_default_scaling("enth_mass_phase", 1e-5, index="Liq") self.set_default_scaling("enth_mass_phase", 1e-6, index="Vap") self.set_default_scaling("pressure_sat", 1e-5) self.set_default_scaling("cp_phase", 1e-3, index="Liq") self.set_default_scaling("cp_phase", 1e-3, index="Vap") self.set_default_scaling("dh_vap", 1e-6) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ "flow_mass_phase_comp": { "method": None }, "temperature": { "method": None }, "pressure": { "method": None }, "dens_mass_phase": { "method": "_dens_mass_phase" }, "flow_vol_phase": { "method": "_flow_vol_phase" }, "flow_vol": { "method": "_flow_vol" }, "flow_mol_phase_comp": { "method": "_flow_mol_phase_comp" }, "mole_frac_phase_comp": { "method": "_mole_frac_phase_comp" }, "pressure_sat": { "method": "_pressure_sat" }, "enth_mass_phase": { "method": "_enth_mass_phase" }, "enth_flow_phase": { "method": "_enth_flow_phase" }, "cp_phase": { "method": "_cp_phase" }, "dh_vap": { "method": "_dh_vap" }, }) obj.add_default_units({ "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, })
class WaterParameterBlockData(PhysicalParameterBlock): """ Property Parameter Block Class Defines component and phase lists, along with base units and constant parameters. """ CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( 'database', ConfigValue( description= 'An instance of a WaterTAP Database to use for parameters.')) CONFIG.declare( 'water_source', ConfigValue( description= 'Water source to use when looking up parameters from database.')) CONFIG.declare( "solute_list", ConfigValue( domain=list, description="List of solute species of interest. If None, will use " "all species defined in the water_source provided.")) def build(self): ''' Callable method for Block construction. ''' super().build() self._state_block_class = WaterStateBlock self.Liq = LiquidPhase() self.H2O = Solvent() # Get component set from database if provided comp_set = None if self.config.database is not None: comp_set = self.config.database.get_solute_set( self.config.water_source) # Check definition of solute list solute_list = self.config.solute_list if solute_list is None: # No user-provided solute list, look up list from database if comp_set is None: # No solute list in database and none provided. raise ConfigurationError( f"{self.name} no solute_list or database was defined. " f"Users must provide at least one of these arguments.") else: solute_list = comp_set elif self.config.database is not None: # User provided custom list and database - check that all # components are supported for j in solute_list: if j not in comp_set: _log.info(f"{self.name} component {j} is not defined in " f"the water_sources database file.") else: # User provided list but no database - assume they know what they # are doing pass for j in solute_list: self.add_component(str(j), Solute()) # Define default value for mass density of solution self.dens_mass_default = 1000 * pyunits.kg / pyunits.m**3 # Define default value for dynamic viscosity of solution self.visc_d_default = 0.001 * pyunits.kg / pyunits.m / pyunits.s # --------------------------------------------------------------------- # Set default scaling factors self.default_scaling_factor = { ("flow_vol"): 1e3, ("conc_mass_comp"): 1e2 } @classmethod def define_metadata(cls, obj): obj.add_default_units({ 'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K, }) obj.add_properties({ 'flow_mass_comp': { 'method': None }, 'flow_vol': { 'method': '_flow_vol' }, 'conc_mass_comp': { 'method': '_conc_mass_comp' }, 'dens_mass': { 'method': '_dens_mass' }, 'visc_d': { 'method': '_visc_d' } })
class NaClParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(NaClParameterData, self).build() self.state_block_class = IdealStateBlock self.component_list = Set(initialize=['H2O', 'NaCl']) self.phase_list = Set(initialize=['Liq'], ordered=True) # List of components in each phase (optional) self.phase_comp = {"Liq": self.component_list} # Source: google mw_comp_data = {'H2O': 18.0E-3, 'NaCl': 58.4E-3} self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight Kg/mol") @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mass': { 'method': None, 'units': 'g/s' }, 'flow_mass_comp': { 'method': None, 'units': 'g/s' }, 'mass_frac': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'dens_mass': { 'method': '_dens_mass', 'units': 'g/m3' }, 'dens_mass_comp': { 'method': '_dens_mass_comp', 'units': 'g/m3' }, 'pressure_osm': { 'method': '_pressure_osm', 'units': 'Pa' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'g', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'g' })
class PropParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(PropParameterData, self).build() self._state_block_class = PropStateBlock # phases self.Liq = LiquidPhase() # components self.H2O = Solvent() self.Na = Solute() self.Ca = Solute() self.Mg = Solute() self.SO4 = Solute() self.Cl = Solute() # molecular weight mw_comp_data = {'H2O': 18.015e-3, 'Na': 22.990e-3, 'Ca': 40.078e-3, 'Mg': 24.305e-3, 'SO4': 96.06e-3, 'Cl': 35.453e-3} self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), units=pyunits.kg / pyunits.mol, doc="Molecular weight") self.dens_mass = Param(mutable=False, initialize=1000, units=pyunits.kg / pyunits.m**3, doc="Density") self.cp = Param(mutable=False, initialize=4.2e3, units=pyunits.J / (pyunits.kg * pyunits.K)) # ---default scaling--- self.set_default_scaling('temperature', 1e-2) self.set_default_scaling('pressure', 1e-6) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties( {'flow_mass_phase_comp': {'method': None}, 'temperature': {'method': None}, 'pressure': {'method': None}, 'mass_frac_phase_comp': {'method': '_mass_frac_phase_comp'}, 'flow_vol': {'method': '_flow_vol'}, 'flow_mol_phase_comp': {'method': '_flow_mol_phase_comp'}, 'conc_mol_phase_comp': {'method': '_conc_mol_phase_comp'}, 'enth_flow': {'method': '_enth_flow'}, }) obj.add_default_units({'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K})
class HDAParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(HDAParameterData, self).build() self._state_block_class = HDAStateBlock self.benzene = Component() self.toluene = Component() self.methane = Component() self.hydrogen = Component() self.diphenyl = Component() self.Vap = VaporPhase() # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, units=pyunits.Pa, doc='Reference pressure') self.temperature_ref = Param(mutable=True, default=298.15, units=pyunits.K, doc='Reference temperature') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid self.mw_comp = Param(self.component_list, mutable=False, initialize={'benzene': 78.1136E-3, 'toluene': 92.1405E-3, 'hydrogen': 2.016e-3, 'methane': 16.043e-3, 'diphenyl': 154.212e-4}, units=pyunits.kg/pyunits.mol, doc="Molecular weight") # Constants for specific heat capacity, enthalpy # Sources: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid self.cp_mol_ig_comp_coeff_A = Var( self.component_list, initialize={"benzene": -3.392E1, "toluene": -2.435E1, "hydrogen": 2.714e1, "methane": 1.925e1, "diphenyl": -9.707e1}, units=pyunits.J/pyunits.mol/pyunits.K, doc="Parameter A for ideal gas molar heat capacity") self.cp_mol_ig_comp_coeff_A.fix() self.cp_mol_ig_comp_coeff_B = Var( self.component_list, initialize={"benzene": 4.739E-1, "toluene": 5.125E-1, "hydrogen": 9.274e-3, "methane": 5.213e-2, "diphenyl": 1.106e0}, units=pyunits.J/pyunits.mol/pyunits.K**2, doc="Parameter B for ideal gas molar heat capacity") self.cp_mol_ig_comp_coeff_B.fix() self.cp_mol_ig_comp_coeff_C = Var( self.component_list, initialize={"benzene": -3.017E-4, "toluene": -2.765E-4, "hydrogen": -1.381e-5, "methane": -8.855e-4, "diphenyl": -8.855e-4}, units=pyunits.J/pyunits.mol/pyunits.K**3, doc="Parameter C for ideal gas molar heat capacity") self.cp_mol_ig_comp_coeff_C.fix() self.cp_mol_ig_comp_coeff_D = Var( self.component_list, initialize={"benzene": 7.130E-8, "toluene": 4.911E-8, "hydrogen": 7.645e-9, "methane": -1.132e-8, "diphenyl": 2.790e-7}, units=pyunits.J/pyunits.mol/pyunits.K**4, doc="Parameter D for ideal gas molar heat capacity") self.cp_mol_ig_comp_coeff_D.fix() # Source: NIST Webook, https://webbook.nist.gov/, retrieved 11/3/2020 self.enth_mol_form_vap_comp_ref = Var( self.component_list, initialize={"benzene": -82.9e3, "toluene": -50.1e3, "hydrogen": 0, "methane": -75e3, "diphenyl": -180e3}, units=pyunits.J/pyunits.mol, doc="Standard heat of formation at reference state") self.enth_mol_form_vap_comp_ref.fix() @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties( {'flow_mol': {'method': None}, 'mole_frac_comp': {'method': None}, 'temperature': {'method': None}, 'pressure': {'method': None}, 'mw_comp': {'method': None}, 'dens_mol': {'method': None}, 'enth_mol': {'method': '_enth_mol'}}) obj.add_default_units({'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K})
class CoagulationParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): """ Callable method for Block construction. """ super(CoagulationParameterData, self).build() self._state_block_class = CoagulationStateBlock # phases self.Liq = LiquidPhase() # components self.H2O = Component() self.TSS = Component() self.TDS = Component() self.Sludge = Component() # heat capacity of liquid self.cp = Param(mutable=False, initialize=4184, units=pyunits.J / (pyunits.kg * pyunits.K)) # reference density of liquid self.ref_dens_liq = Param( domain=Reals, initialize=999.26, mutable=True, units=pyunits.kg / pyunits.m**3, doc='Reference water mass density parameter @ 0 oC and no salts') # change in liquid density with increasing mass fraction of salts/solids self.dens_slope = Param( domain=Reals, initialize=879.04, mutable=True, units=pyunits.kg / pyunits.m**3, doc= 'Relative increase in liquid density with mass fraction of salts') # adjustment parameters for density change with temperature # Density calculation as a function of temperature and pressure # -------------------------------------------------------------- # Engineering Toolbox. Water - Density, Specific Weight, and # Thermal Expansion Coefficients. (2003) https://www.engineeringtoolbox.com/ # water-density-specific-weight-d_595.html [Accessed 02-01-2022] self.dens_param_A = Param( domain=Reals, initialize=-2.9335E-6, mutable=True, units=pyunits.K**-2, doc='Density correction parameter A for temperature variation') self.dens_param_B = Param( domain=Reals, initialize=0.001529811, mutable=True, units=pyunits.K**-1, doc='Density correction parameter B for temperature variation') self.dens_param_C = Param( domain=Reals, initialize=0.787973, mutable=True, units=pyunits.dimensionless, doc='Density correction parameter C for temperature variation') # Correction factors for changes in density with changes in pressure self.ref_pressure_correction = Param( domain=Reals, initialize=1.0135, mutable=True, units=pyunits.dimensionless, doc='Density reference correction parameter for changes in pressure' ) self.ref_pressure_slope = Param( domain=Reals, initialize=4.9582E-10, mutable=True, units=pyunits.Pa**-1, doc='Slope of density change as a function of pressure') # reference density of solids self.ref_dens_sol = Param( domain=Reals, initialize=2600, mutable=True, units=pyunits.kg / pyunits.m**3, doc='Reference dry solid mass density parameter') # ---default scaling--- self.set_default_scaling('temperature', 1e-2) self.set_default_scaling('pressure', 1e-6) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mass_phase_comp': { 'method': None }, 'temperature': { 'method': None }, 'pressure': { 'method': None }, 'mass_frac_phase_comp': { 'method': '_mass_frac_phase_comp' }, 'dens_mass_phase': { 'method': '_dens_mass_phase' }, 'flow_vol_phase': { 'method': '_flow_vol_phase' }, 'conc_mass_phase_comp': { 'method': '_conc_mass_phase_comp' }, 'enth_flow': { 'method': '_enth_flow' }, }) obj.add_default_units({ 'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K })
class NaClParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(NaClParameterData, self).build() self.state_block_class = IdealStateBlock self.component_list = Set(initialize=['H2O', 'NaCl']) self.phase_list = Set(initialize=['Liq'], ordered=True) # List of components in each phase (optional) self.phase_comp = {"Liq": self.component_list} # Source: google mw_comp_data = {'H2O': 18.0E-3, 'NaCl': 58.4E-3} self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight Kg/mol") @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mass': { 'method': None, 'units': 'g/s' }, 'mass_frac': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'dens_mass': { 'method': '_dens_mass', 'units': 'kg/m3' }, 'viscosity': { 'method': '_viscosity', 'units': 'Pa-s' }, 'dens_mass_comp': { 'method': '_dens_mass_comp', 'units': 'kg/m3' }, 'osm_coeff': { 'method': '_osm_coeff', 'units': 'none' }, 'pressure_osm': { 'method': '_pressure_osm', 'units': 'Pa' }, 'enth_mass_liq': { 'method': '_enth_mass_liq', 'units': 'J/kg' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'kg', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'g' }) # parameters R = 8.314 # gas constant [J/mol-K] MW = 58.44 # molecular weight [g/mol] osm_coeff_data = { 'a1': 8.9453e-1, 'a2': 4.1561e-4, 'a3': -4.6262e-6, 'a4': 2.2211e-11, 'a5': -1.1445e-1, 'a6': -1.4783e-3, 'a7': -1.3526e-8, 'a8': 7.0132, 'a9': 5.696e-2, 'a10': -2.8624e-4 }
class PhysicalParameterData(PhysicalParameterBlock): """ Vapor Phase Property Parameter Block Class Contains parameters and indexing sets associated with vapor phase properties for amine-based scrubbing process. """ # Remove zero flow components in the vapor phase # using config to set the vapor components according to process type CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare("process_type", ConfigValue( default=ProcessType.absorber, domain=In(ProcessType), description="Flag indicating the type of process", doc="""Flag indicating either absorption or stripping process. **default** - ProcessType.absorber. **Valid values:** { **ProcessType.absorber** - absorption process, **ProcessType.stripper** - stripping process.}""")) def build(self): ''' Callable method for Block construction. ''' ''' Create Component objects components created using the component class are added to the component_list object which is used by the framework ''' super(PhysicalParameterData, self).build() if (self.config.process_type == ProcessType.stripper): self.CO2 = Component() self.H2O = Component() elif (self.config.process_type == ProcessType.absorber): self.CO2 = Component() self.H2O = Component() self.O2 = Component() self.N2 = Component() self._state_block_class = VaporStateBlock # Create Phase object self.Vap = VaporPhase() # Thermodynamic reference state self.pressure_ref = Param(within=PositiveReals, mutable=True, default=101325, units=pyunits.Pa, doc='Reference pressure ') self.temperature_ref = Param(default=298.15, units=pyunits.K, doc='Thermodynamic Reference Temperature [K]') # Mol. weights of vapor component - units = kg/mol. mw_comp_dict_all = {'CO2': 0.04401, 'H2O': 0.01802, 'O2': 0.032, 'N2': 0.02801} mw_comp_dict = {} for i in self.component_list: mw_comp_dict[i] = mw_comp_dict_all[i] self.mw_comp = Param( self.component_list, mutable=False, initialize=mw_comp_dict, units=pyunits.kg / pyunits.mol, doc="Molecular weights of vapor components") # from Van Ness, J. Smith (appendix C): CO2,N2,O2,WATER # cpig/R = A + BT + CT^-2 # unit depends on unit of gas constant(J/mol.K) cp_param_dict_all = { ('O2', 1): 3.639 * CONST.gas_constant, ('O2', 2): 0.506E-3 * CONST.gas_constant, ('O2', 3): -0.227E5 * CONST.gas_constant, ('CO2', 1): 5.457 * CONST.gas_constant, ('CO2', 2): 1.045E-3 * CONST.gas_constant, ('CO2', 3): -1.157E5 * CONST.gas_constant, ('H2O', 1): 3.47 * CONST.gas_constant, ('H2O', 2): 1.45E-3 * CONST.gas_constant, ('H2O', 3): 0.121E5 * CONST.gas_constant, ('N2', 1): 3.28 * CONST.gas_constant, ('N2', 2): 0.593E-3 * CONST.gas_constant, ('N2', 3): 0.04E5 * CONST.gas_constant } cp_param_dict = {} for i in self.component_list: for j in [1, 2, 3]: cp_param_dict[i, j] = cp_param_dict_all[i, j] self.cp_param = Param(self.component_list, range(1, 4), mutable=False, initialize=cp_param_dict, units=pyunits.J / (pyunits.mol * pyunits.K), doc="Ideal gas heat capacity parameters") # Viscosity constants #CO2 & H2O # calculated from :C1*T^(C2)/(1+C3/T) # Reference: Perry and Green Handbook; McGraw Hill,8th edition 2008 #O2 & N2 # calculated from Sutherland Formular # C1*(C2 + C3)/(T+C3)*(T/C2)^1.5: # constants C1,C2,C3 in sutherlands' formular are: #C1 = vis_d_ref #C2 = temperature_ref # C3 = sutherland constant visc_d_param_dict_all = { ('N2', 1): 0.01781e-3, ('N2', 2): 300.55, ('N2', 3): 111, ('O2', 1): 0.02018e-3, ('O2', 2): 292.25, ('O2', 3): 127, ('CO2', 1): 2.148e-6, ('CO2', 2): 0.46, ('CO2', 3): 290, ('H2O', 1): 1.7096e-8, ('H2O', 2): 1.1146, ('H2O', 3): 0.0 } visc_d_param_dict = {} for i in self.component_list: for j in [1, 2, 3]: visc_d_param_dict[i, j] = visc_d_param_dict_all[i, j] self.visc_d_param = Param(self.component_list, range(1, 4), mutable=True, initialize=visc_d_param_dict, units=pyunits.Pa * pyunits.s, doc="Dynamic viscosity constants") # Thermal conductivity constants - # Reference: Perry and Green Handbook; McGraw Hill, 8th edition 2008 therm_cond_param_dict_all = {('N2', 1): 0.000331, ('N2', 2): 0.7722, ('N2', 3): 16.323, ('N2', 4): 373.72, ('CO2', 1): 3.69, ('CO2', 2): -0.3838, ('CO2', 3): 964, ('CO2', 4): 1.86e6, ('H2O', 1): 6.204e-6, ('H2O', 2): 1.3973, ('H2O', 3): 0, ('H2O', 4): 0, ('O2', 1): 0.00045, ('O2', 2): 0.7456, ('O2', 3): 56.699, ('O2', 4): 0.0} therm_cond_param_dict = {} for i in self.component_list: for j in [1, 2, 3, 4]: therm_cond_param_dict[i, j] = therm_cond_param_dict_all[i, j] self.therm_cond_param = Param(self.component_list, range(1, 5), mutable=True, initialize=therm_cond_param_dict, units=pyunits.W / pyunits.m / pyunits.K, doc="Thermal conductivity constants") # Diffusion Coefficient(binary) constants - # Diffusion volumes in Fuller-Schettler-Giddings correlation # for estimating binary diffusivities of components in vapor phase # Reference: Table 3.1 pp 71 Seader Henley (2006) diffus_binary_param_dict_all = { 'N2': 18.5, 'CO2': 26.7, 'H2O': 13.1, 'O2': 16.3} diffus_binary_param_dict = {} for i in self.component_list: diffus_binary_param_dict[i] = diffus_binary_param_dict_all[i] self.diffus_binary_param = \ Param(self.component_list, initialize=diffus_binary_param_dict, units=pyunits.m**2 / pyunits.s, doc="Diffusion volume parameter for binary diffusivity") @classmethod def define_metadata(cls, obj): obj.add_properties({ 'flow_mol': {'method': None, 'units': 'mol/s'}, 'pressure': {'method': None, 'units': 'Pa'}, 'temperature': {'method': None, 'units': 'K'}, 'mole_frac_comp': {'method': None, 'units': None}, 'flow_mol_comp': {'method': '_flow_mol_comp', 'units': 'mol/s'}, 'mw': {'method': '_mw', 'units': 'kg/mol'}, 'conc_mol': {'method': '_conc_mol', 'units': 'mol/m^3'}, 'conc_mol_comp': {'method': '_conc_mol_comp', 'units': 'mol/m^3'}, 'dens_mass': {'method': '_dens_mass', 'units': 'kg/m^3'}, 'cp_mol': {'method': '_cp_mol', 'units': 'J/mol.K'}, 'cp_mol_mean': {'method': '_cp_mol_mean', 'units': 'J/mol.K'}, 'cp_mol_comp': {'method': '_cp_mol_comp', 'units': 'J/mol.K'}, 'cp_mol_comp_mean': {'method': '_cp_mol_comp_mean', 'units': 'J/mol.K'}, 'enth_mean': {'method': '_enth_mean', 'units': 'J/s'}, 'enth_vap_density': {'method': '_enth_vap_density', 'units': 'J/m^3'}, 'diffus': {'method': '_diffus', 'units': 'm^2/s'}, 'visc_d': {'method': '_visc_d', 'units': 'kg/m.s'}, 'visc_d_comp': {'method': '_visc_d_comp', 'units': 'kg/m.s'}, 'therm_cond': {'method': '_therm_cond', 'units': 'J/m.K.s'}, 'therm_cond_comp': {'method': '_therm_cond_comp', 'units': 'J/m.K.s'}}) obj.add_default_units({'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K})
class PropertyInterrogatorData(PhysicalParameterBlock): """ Interrogator Parameter Block Class This class contains the methods and attributes for recording and displaying the properties requried by the flowsheet. """ CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "phase_list", ConfigValue( domain=dict, description="User defined phase list. Dict with form {name: Type}") ) CONFIG.declare( "component_list", ConfigValue( domain=dict, description= "User defined component list. Dict with form {name: Type}")) def build(self): ''' Callable method for Block construction. ''' super(PropertyInterrogatorData, self).build() self._state_block_class = InterrogatorStateBlock # Phase objects if self.config.phase_list is None: self.Liq = LiquidPhase() self.Vap = VaporPhase() else: for p, t in self.config.phase_list.items(): if t is None: t = Phase elif not isclass(t) or not issubclass(t, Phase): raise ConfigurationError( f"{self.name} invalid phase type {t} (for phase {p})." f" Type must be a subclass of Phase.") self.add_component(p, t()) # Component objects if self.config.component_list is None: self.A = Component() self.B = Component() else: for j, t in self.config.component_list.items(): if t is None: t = Component elif not isclass(t) or not issubclass(t, Component): raise ConfigurationError( f"{self.name} invalid component type {t} (for " f"component {j}). Type must be a subclass of " f"Component.") self.add_component(j, t()) # Set up dict to record property calls self.required_properties = {} # Dummy phase equilibrium definition so we can handle flash cases self.phase_equilibrium_idx = Set(initialize=[1]) self.phase_equilibrium_list = \ {1: ["A", ("Vap", "Liq")]} def list_required_properties(self): """ Method to list all thermophysical properties required by the flowsheet. Args: None Returns: A list of properties required """ return list(self.required_properties) def list_models_requiring_property(self, prop): """ Method to list all models in the flowsheet requiring the given property. Args: prop : the property of interest Returns: A list of unit model names which require prop """ try: return self.required_properties[prop] except KeyError: raise KeyError( "Property {} does not appear in required_properties. " "Please check the spelling of the property that you are " "interested in.".format(prop)) def list_properties_required_by_model(self, model): """ Method to list all thermophysical properties required by a given unit model. Args: model : the unit model of interest. Can be given as either a model component or the unit name as a string Returns: A list of thermophysical properties required by model """ prop_list = [] if not isinstance(model, str): model = model.name for k, v in self.required_properties.items(): if model in v: prop_list.append(k) if len(prop_list) < 1: raise ValueError( "Model {} does not appear in the flowsheet. Please check " "the spelling of the model provided.") else: return prop_list def print_required_properties(self, ostream=None): """ Method to print a summary of the thermophysical properties required by the flowsheet. Args: ostream : output stream to print to. If not provided will print to sys.stdout Returns: None """ if ostream is None: ostream = sys.stdout # Write header max_str_length = 74 tab = " " * 4 ostream.write("\n" + "=" * max_str_length + "\n") ostream.write("Property Interrogator Summary" + "\n") ostream.write("\n" + "The Flowsheet requires the following properties " + "(times required):" + "\n" + "\n") for k, v in self.required_properties.items(): lead_str = tab + k trail_str = str(len(v)) mid_str = " " * (max_str_length - len(lead_str) - len(trail_str)) ostream.write(lead_str + mid_str + trail_str + "\n") ostream.write( "\n" + "Note: User constraints may require additional properties " + "which are not" + "\n" + "reported here." + "\n") def print_models_requiring_property(self, prop, ostream=None): """ Method to print a summary of the models in the flowsheet requiring a given property. Args: prop : the property of interest. ostream : output stream to print to. If not provided will print to sys.stdout Returns: None """ if ostream is None: ostream = sys.stdout tab = " " * 4 ostream.write("\n") ostream.write(f"The following models in the Flowsheet " f"require {prop}:" + "\n") for m in self.required_properties[prop]: ostream.write(tab + m + "\n") def print_properties_required_by_model(self, model, ostream=None): """ Method to print a summary of the thermophysical properties required by a given unit model. Args: model : the unit model of interest. ostream : output stream to print to. If not provided will print to sys.stdout Returns: None """ if not isinstance(model, str): model = model.name if ostream is None: ostream = sys.stdout tab = " " * 4 ostream.write("\n") ostream.write(f"The following properties are required by model " f"{model}:" + "\n") for m in self.list_properties_required_by_model(model): ostream.write(tab + m + "\n") @classmethod def define_metadata(cls, obj): obj.add_default_units({ 'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K })
class NaClParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(NaClParameterData, self).build() self._state_block_class = NaClStateBlock # components self.H2O = Solvent() self.NaCl = Solute() # phases self.Liq = LiquidPhase() # reference # this package is developed from Bartholomew & Mauter (2019) https://doi.org/10.1016/j.memsci.2018.11.067 # the enthalpy calculations are from Sharqawy et al. (2010) http://dx.doi.org/10.5004/dwt.2010.1079 # molecular weight mw_comp_data = {'H2O': 18.01528E-3, 'NaCl': 58.44E-3} self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), units=pyunits.kg / pyunits.mol, doc="Molecular weight kg/mol") # mass density parameters, eq 4 in Bartholomew dens_mass_param_dict = {'0': 995, '1': 756} self.dens_mass_param = Var(dens_mass_param_dict.keys(), domain=Reals, initialize=dens_mass_param_dict, units=pyunits.kg / pyunits.m**3, doc='Mass density parameters') # dynamic viscosity parameters, eq 5 in Bartholomew visc_d_param_dict = {'0': 9.80E-4, '1': 2.15E-3} self.visc_d_param = Var(visc_d_param_dict.keys(), domain=Reals, initialize=visc_d_param_dict, units=pyunits.Pa * pyunits.s, doc='Dynamic viscosity parameters') # diffusivity parameters, eq 6 in Bartholomew diffus_param_dict = { '0': 1.51e-9, '1': -2.00e-9, '2': 3.01e-8, '3': -1.22e-7, '4': 1.53e-7 } self.diffus_param = Var(diffus_param_dict.keys(), domain=Reals, initialize=diffus_param_dict, units=pyunits.m**2 / pyunits.s, doc='Dynamic viscosity parameters') # osmotic coefficient parameters, eq. 3b in Bartholomew osm_coeff_param_dict = {'0': 0.918, '1': 8.89e-2, '2': 4.92} self.osm_coeff_param = Var(osm_coeff_param_dict.keys(), domain=Reals, initialize=osm_coeff_param_dict, units=pyunits.dimensionless, doc='Osmotic coefficient parameters') # TODO: update for NaCl solution, relationship from Sharqawy is for seawater # specific enthalpy parameters, eq. 55 and 43 in Sharqawy (2010) self.enth_mass_param_A1 = Var(within=Reals, initialize=124.790, units=pyunits.J / pyunits.kg, doc='Specific enthalpy parameter A1') self.enth_mass_param_A2 = Var(within=Reals, initialize=4203.075, units=(pyunits.J / pyunits.kg) * pyunits.K**-1, doc='Specific enthalpy parameter A2') self.enth_mass_param_A3 = Var(within=Reals, initialize=-0.552, units=(pyunits.J / pyunits.kg) * pyunits.K**-2, doc='Specific enthalpy parameter A3') self.enth_mass_param_A4 = Var(within=Reals, initialize=0.004, units=(pyunits.J / pyunits.kg) * pyunits.K**-3, doc='Specific enthalpy parameter A4') self.enth_mass_param_B1 = Var(within=Reals, initialize=27062.623, units=pyunits.dimensionless, doc='Specific enthalpy parameter B1') self.enth_mass_param_B2 = Var(within=Reals, initialize=4835.675, units=pyunits.dimensionless, doc='Specific enthalpy parameter B2') # traditional parameters are the only Vars currently on the block and should be fixed for v in self.component_objects(Var): v.fix() # ---default scaling--- self.set_default_scaling('temperature', 1e-2) self.set_default_scaling('pressure', 1e-6) self.set_default_scaling('dens_mass_phase', 1e-3, index='Liq') self.set_default_scaling('visc_d_phase', 1e3, index='Liq') self.set_default_scaling('diffus_phase', 1e9, index='Liq') self.set_default_scaling('osm_coeff', 1e0) self.set_default_scaling('enth_mass_phase', 1e-5, index='Liq') @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mass_phase_comp': { 'method': None }, 'temperature': { 'method': None }, 'pressure': { 'method': None }, 'mass_frac_phase_comp': { 'method': '_mass_frac_phase_comp' }, 'dens_mass_phase': { 'method': '_dens_mass_phase' }, 'flow_vol_phase': { 'method': '_flow_vol_phase' }, 'flow_vol': { 'method': '_flow_vol' }, 'conc_mass_phase_comp': { 'method': '_conc_mass_phase_comp' }, 'flow_mol_phase_comp': { 'method': '_flow_mol_phase_comp' }, 'mole_frac_phase_comp': { 'method': '_mole_frac_phase_comp' }, 'molality_comp': { 'method': '_molality_comp' }, 'diffus_phase': { 'method': '_diffus_phase' }, 'visc_d_phase': { 'method': '_visc_d_phase' }, 'osm_coeff': { 'method': '_osm_coeff' }, 'pressure_osm': { 'method': '_pressure_osm' }, 'enth_mass_phase': { 'method': '_enth_mass_phase' }, 'enth_flow': { 'method': '_enth_flow' } }) obj.add_default_units({ 'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K })
class GenericParameterData(PhysicalParameterBlock): """ General Property Parameter Block Class """ CONFIG = PhysicalParameterBlock.CONFIG() # General options CONFIG.declare( "component_list", ConfigValue( description="List of components in material", doc="""A list of names for the components of interest in the mixture. """)) CONFIG.declare( "phase_list", ConfigValue( description="List of phases of interest", doc="""A list of phases of interest in the mixture for the property package.""")) CONFIG.declare( "phase_component_list", ConfigValue( description="List of components in each phase", doc= """A dict of component_lists for each phase. Keys should correspond to members of phase_list, and each value should be a list of component names.""")) CONFIG.declare( "state_definition", ConfigValue( description="Choice of State Variable", doc="""Flag indicating the set of state variables to use for property package. Values should be a valid Python method which creates the required state variables. Default = state_methods.FPHx""")) CONFIG.declare( "state_bounds", ConfigValue( domain=dict, description="Bounds for state variables", doc="""A dict containing bounds to use for state variables.""")) CONFIG.declare( "phase_equilibrium_formulation", ConfigValue( default=None, description="Phase equilibrium formulation to use", doc="""Flag indicating what formulation to use for calculating phase equilibrium. Value should be a valid Python method or None. Default = None, indicating no phase equilibrium will occur.""")) CONFIG.declare( "phase_equilibrium_dict", ConfigValue( default=None, description="Phase equilibrium reactions to be modeled", doc="""Dict describing what phase equilibrium reactions should be included in the property package. Keys should be names from component_list, and values should be a 2-tuple of phases from phase_list which should be in equilibrium.""")) CONFIG.declare( "temperature_bubble", ConfigValue( description="Method to use to calculate bubble temperature", doc="""Flag indicating what formulation to use for calculating bubble temperature. Value should be a valid Python method.""")) CONFIG.declare( "temperature_dew", ConfigValue( description="Method to use to calculate dew temperature", doc="""Flag indicating what formulation to use for calculating dew temperature. Value should be a valid Python method.""")) CONFIG.declare( "pressure_bubble", ConfigValue( description="Method to use to calculate bubble pressure", doc="""Flag indicating what formulation to use for calculating bubble pressure. Value should be a valid Python method.""")) CONFIG.declare( "pressure_dew", ConfigValue( description="Method to use to calculate dew pressure", doc="""Flag indicating what formulation to use for calculating dew pressure. Value should be a valid Python method.""")) # Equation of state options CONFIG.declare( "equation_of_state", ConfigValue( description="Equation of state for each phase", doc="""Flag containing a dict indicating the equation of state for each phase. Value should be a dict with keys for each valid phase and values being a valid Python module with the necessary methods for the desired equation of state.""")) # Pure component property options CONFIG.declare( "dens_mol_liq_comp", ConfigValue( description="Method to use to calculate liquid phase molar density", doc= """Flag indicating what method to use when calculating liquid phase molar density.""")) CONFIG.declare( "enth_mol_liq_comp", ConfigValue( description="Method to calculate liquid component molar enthalpies", doc= """Flag indicating what method to use when calculating liquid phase component molar enthalpies.""")) CONFIG.declare( "enth_mol_ig_comp", ConfigValue( description= "Method to calculate ideal gas component molar enthalpies", doc="""Flag indicating what method to use when calculating ideal gas phase component molar enthalpies.""")) CONFIG.declare( "entr_mol_liq_comp", ConfigValue( description="Method to calculate liquid component molar entropies", doc= """Flag indicating what method to use when calculating liquid phase component molar entropies.""")) CONFIG.declare( "entr_mol_ig_comp", ConfigValue( description= "Method to calculate ideal gas component molar entropies", doc="""Flag indicating what method to use when calculating ideal gas phase component molar entropies.""")) CONFIG.declare( "pressure_sat_comp", ConfigValue( description="Method to use to calculate saturation pressure", doc="""Flag indicating what method to use when calculating saturation pressure. Value should be a valid Python method which takes two arguments: temperature and a component name.""")) def build(self): ''' Callable method for Block construction. ''' # Call super.build() to initialize Block super(GenericParameterData, self).build() # Call configure method to set construction arguments self.configure() # Build core components self.state_block_class = GenericStateBlock if self.config.phase_component_list is not None: # Check if phase list provided and cross-validate if self.config.phase_list is not None: # Phase list provided, cross-validate for p in self.config.phase_component_list: if p not in self.config.phase_list: raise ConfigurationError( "{} mismatch between phase_list and " "phase_component_list. Phase {} appears in " "phase_component_list but not phase_list.".format( self.name, p)) for p in self.config.phase_list: if p not in self.config.phase_component_list: raise ConfigurationError( "{} mismatch between phase_list and " "phase_component_list. Phase {} appears in " "phase_list but not phase_component_list.".format( self.name, p)) # Build phase_list if cross-validation passes self.phase_list = Set(initialize=self.config.phase_list, ordered=True) else: # No phase_list provided, build from phase_component_list self.phase_list = Set( initialize=[p for p in self.config.phase_component_list], ordered=True) if self.config.component_list is not None: # Component list provided, cross-validate for p in self.config.phase_component_list: for j in self.config.phase_component_list[p]: if j not in self.config.component_list: raise ConfigurationError( "{} mismatch between component_list and " "phase_component_list. Component {} appears in" " phase_component_list but not component_list." .format(self.name, j)) for j in self.config.component_list: xcheck = False for p in self.config.phase_component_list: if j in self.config.phase_component_list[p]: xcheck = True break if not xcheck: raise ConfigurationError( "{} mismatch between component_list and " "phase_component_list. Component {} appears in" " component_list but not phase_component_list.". format(self.name, j)) # Build component_list if cross-validation passes self.component_list = Set( initialize=self.config.component_list, ordered=True) else: # No component_list provided, build from phase_component_list c_list = [] for p in self.config.phase_component_list: for j in self.config.phase_component_list[p]: if j not in c_list: c_list.append(j) self.component_list = Set(initialize=c_list, ordered=True) # All validation passed, build phase_component_set pc_set = [] for p in self.config.phase_component_list: for j in self.config.phase_component_list[p]: pc_set.append((p, j)) self._phase_component_set = Set(initialize=pc_set, ordered=True) elif (self.config.phase_list is not None and self.config.component_list is not None): # Have phase and component lists # Assume all components in all phases self.phase_list = Set(initialize=self.config.phase_list, ordered=True) self.component_list = Set(initialize=self.config.component_list, ordered=True) # Create phase-component set pc_set = [] for p in self.phase_list: for j in self.component_list: pc_set.append((p, j)) self._phase_component_set = Set(initialize=pc_set, ordered=True) else: # User has not provided sufficient information. if self.config.component_list is None: raise ConfigurationError( "{} Generic Property Package was not provided with a " "component_list or a phase_component_list. Users must " "provide either at least one of these arguments".format( self.name)) if self.config.phase_list is None: raise ConfigurationError( "{} Generic Property Package was not provided with a " "phase_list or a phase_component_list. Users must " "provide either at least one of these arguments".format( self.name)) # Validate state definition if self.config.state_definition is None: raise ConfigurationError( "{} Generic Property Package was not provided with a " "state_definition configuration argument. Please fix " "your property parameter definition to include this " "configuration argument.".format(self.name)) # Validate equation of state if self.config.equation_of_state is None: raise ConfigurationError( "{} Generic Property Package was not provided with an " "equation_of_state configuration argument. Please fix " "your property parameter definition to include this " "configuration argument.".format(self.name)) if not isinstance(self.config.equation_of_state, dict): raise ConfigurationError( "{} Generic Property Package was provided with an invalid " "equation_of_state configuration argument. Argument must " "be a dict with phases as keys.".format(self.name)) if len(self.config.equation_of_state) != len(self.phase_list): raise ConfigurationError( "{} Generic Property Package was provided with an invalid " "equation_of_state configuration argument. A value must " "be present for each phase.".format(self.name)) for p in self.config.equation_of_state: if p not in self.phase_list: raise ConfigurationError( "{} Generic Property Package unrecognised phase {} in " "equation_of_state configuration argument. Keys must be " "valid phases.".format(self.name, p)) # Validate that user provided either both a phase equilibrium # formulation and a dict of phase equilibria or neither if ((self.config.phase_equilibrium_formulation is not None) ^ (self.config.phase_equilibrium_dict is not None)): raise ConfigurationError( "{} Generic Property Package provided with only one of " "phase_equilibrium_formulation and phase_equilibrium_dict." " Either both of these arguments need to be provided or " "neither.".format(self.name)) # Validate and build phase equilibrium list if self.config.phase_equilibrium_dict is not None: if not isinstance(self.config.phase_equilibrium_dict, dict): raise ConfigurationError( "{} Generic Property Package provided with invalid " "phase_equilibrium_dict - value must be a dict. " "Please see the documentation for the correct form.". format(self.name)) # Validate phase_equilibrium_dict for v in self.config.phase_equilibrium_dict.values(): if not (isinstance(v, list) and len(v) == 2): raise ConfigurationError( "{} Generic Property Package provided with invalid " "phase_equilibrium_dict, {}. Values in dict must be " "lists containing 2 values.".format(self.name, v)) if v[0] not in self.component_list: raise ConfigurationError( "{} Generic Property Package provided with invalid " "phase_equilibrium_dict. First value in each list " "must be a valid component, received {}.".format( self.name, v[0])) if not (isinstance(v[1], tuple) and len(v[1]) == 2): raise ConfigurationError( "{} Generic Property Package provided with invalid " "phase_equilibrium_dict. Second value in each list " "must be a 2-tuple containing 2 valid phases, " "received {}.".format(self.name, v[1])) for p in v[1]: if p not in self.phase_list: raise ConfigurationError( "{} Generic Property Package provided with invalid" " phase_equilibrium_dict. Unrecognised phase {} " "in tuple {}".format(self.name, p, v[1])) self.phase_equilibrium_list = self.config.phase_equilibrium_dict pe_set = [] for k in self.config.phase_equilibrium_dict.keys(): pe_set.append(k) self.phase_equilibrium_idx = Set(initialize=pe_set, ordered=True) self.parameters() def configure(self): raise PropertyPackageError( "{} User defined property package failed to define a " "configure method. Please contact the developer of the " "property package with this error.".format(self.name)) def parameters(self): raise PropertyPackageError( "{} User defined property package failed to define a " "parameters method. Please contact the developer of the " "property package with this error.".format(self.name)) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" # TODO : Need to fix to have methods for things that may or may not be # created by state var methods obj.add_properties({ 'flow_mol': { 'method': None, 'units': 'mol/s' }, 'mole_frac_comp': { 'method': None, 'units': 'none' }, 'mole_frac_phase_comp': { 'method': None, 'units': 'none' }, 'phase_frac': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'flow_mol_phase': { 'method': None, 'units': 'mol/s' }, 'dens_mass': { 'method': '_dens_mass', 'units': 'kg/m^3' }, 'dens_mass_phase': { 'method': '_dens_mass_phase', 'units': 'kg/m^3' }, 'dens_mol': { 'method': '_dens_mol', 'units': 'mol/m^3' }, 'dens_mol_phase': { 'method': '_dens_mol_phase', 'units': 'mol/m^3' }, 'enth_mol': { 'method': '_enth_mol', 'units': 'J/mol' }, 'enth_mol_phase': { 'method': '_enth_mol_phase', 'units': 'J/mol' }, 'enth_mol_phase_comp': { 'method': '_enth_mol_phase_comp', 'units': 'J/mol' }, 'entr_mol': { 'method': '_entr_mol', 'units': 'J/mol.K' }, 'entr_mol_phase': { 'method': '_entr_mol_phase', 'units': 'J/mol.K' }, 'entr_mol_phase_comp': { 'method': '_entr_mol_phase_comp', 'units': 'J/mol.K' }, 'fug_phase_comp': { 'method': '_fug_phase_comp', 'units': 'Pa' }, 'fug_coeff_phase_comp': { 'method': '_fug_coeff_phase_comp', 'units': '-' }, 'gibbs_mol': { 'method': '_gibbs_mol', 'units': 'J/mol' }, 'gibbs_mol_phase': { 'method': '_gibbs_mol_phase', 'units': 'J/mol' }, 'gibbs_mol_phase_comp': { 'method': '_gibbs_mol_phase_comp', 'units': 'J/mol' }, 'mw': { 'method': '_mw', 'units': 'kg/mol' }, 'mw_phase': { 'method': '_mw_phase', 'units': 'kg/mol' }, 'pressure_bubble': { 'method': '_pressure_bubble', 'units': 'Pa' }, 'pressure_dew': { 'method': '_pressure_dew', 'units': 'Pa' }, 'pressure_sat_comp': { 'method': '_pressure_sat_comp', 'units': 'Pa' }, 'temperature_bubble': { 'method': '_temperature_bubble', 'units': 'K' }, 'temperature_dew': { 'method': '_temperature_dew', 'units': 'K' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'g', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'mol' })
class IdealParameterData(PhysicalParameterBlock): """ Property Parameter Block Class Contains parameters and indexing sets associated with properties for BTX system. """ # Config block for the _IdealStateBlock CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "valid_phase", ConfigValue(default=('Vap', 'Liq'), domain=In(['Liq', 'Vap', ('Vap', 'Liq'), ('Liq', 'Vap')]), description="Flag indicating the valid phase", doc="""Flag indicating the valid phase for a given set of conditions, and thus corresponding constraints should be included, **default** - ('Vap', 'Liq'). **Valid values:** { **'Liq'** - Liquid only, **'Vap'** - Vapor only, **('Vap', 'Liq')** - Vapor-liquid equilibrium, **('Liq', 'Vap')** - Vapor-liquid equilibrium,}""")) def build(self): ''' Callable method for Block construction. ''' super(IdealParameterData, self).build() self.state_block_class = IdealStateBlock # List of valid phases in property package if self.config.valid_phase == ('Liq', 'Vap') or \ self.config.valid_phase == ('Vap', 'Liq'): self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True) elif self.config.valid_phase == 'Liq': self.phase_list = Set(initialize=['Liq']) else: self.phase_list = Set(initialize=['Vap']) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mol': { 'method': None, 'units': 'mol/s' }, 'mole_frac_comp': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'flow_mol_phase': { 'method': None, 'units': 'mol/s' }, 'dens_mol_phase': { 'method': '_dens_mol_phase', 'units': 'mol/m^3' }, 'pressure_sat': { 'method': '_pressure_sat', 'units': 'Pa' }, 'mole_frac_phase_comp': { 'method': '_mole_frac_phase', 'units': 'no unit' }, 'energy_internal_mol_phase_comp': { 'method': '_energy_internal_mol_phase_comp', 'units': 'J/mol' }, 'energy_internal_mol_phase': { 'method': '_enenrgy_internal_mol_phase', 'units': 'J/mol' }, 'enth_mol_phase_comp': { 'method': '_enth_mol_phase_comp', 'units': 'J/mol' }, 'enth_mol_phase': { 'method': '_enth_mol_phase', 'units': 'J/mol' }, 'entr_mol_phase_comp': { 'method': '_entr_mol_phase_comp', 'units': 'J/mol' }, 'entr_mol_phase': { 'method': '_entr_mol_phase', 'units': 'J/mol' }, 'temperature_bubble': { 'method': '_temperature_bubble', 'units': 'K' }, 'temperature_dew': { 'method': '_temperature_dew', 'units': 'K' }, 'pressure_bubble': { 'method': '_pressure_bubble', 'units': 'Pa' }, 'pressure_dew': { 'method': '_pressure_dew', 'units': 'Pa' }, 'fug_vap': { 'method': '_fug_vap', 'units': 'Pa' }, 'fug_liq': { 'method': '_fug_liq', 'units': 'Pa' }, 'dh_vap': { 'method': '_dh_vap', 'units': 'J/mol' }, 'ds_vap': { 'method': '_ds_vap', 'units': 'J/mol.K' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'g', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'mol' })
class HelmholtzParameterBlockData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare( "phase_presentation", ConfigValue( default=PhaseType.MIX, domain=In(PhaseType), description="Set the way phases are presented to models", doc="""Set the way phases are presented to models. The MIX option appears to the framework to be a mixed phase containing liquid and/or vapor. The mixed option can simplify calculations at the unit model level since it can be treated as a single phase, but unit models such as flash vessels will not be able to treat the phases independently. The LG option presents as two separate phases to the framework. The L or G options can be used if it is known for sure that only one phase is present. **default** - PhaseType.MIX **Valid values:** { **PhaseType.MIX** - Present a mixed phase with liquid and/or vapor, **PhaseType.LG** - Present a liquid and vapor phase, **PhaseType.L** - Assume only liquid can be present, **PhaseType.G** - Assume only vapor can be present}""", ), ) CONFIG.declare( "state_vars", ConfigValue( default=StateVars.PH, domain=In(StateVars), description="State variable set", doc="""The set of state variables to use. Depending on the use, one state variable set or another may be better computationally. Usually pressure and enthalpy are the best choice because they are well behaved during a phase change. **default** - StateVars.PH **Valid values:** { **StateVars.PH** - Pressure-Enthalpy, **StateVars.TPX** - Temperature-Pressure-Quality}""", ), ) def _set_parameters( self, library, state_block_class, component_list, phase_equilibrium_idx, phase_equilibrium_list, mw, temperature_crit, pressure_crit, dens_mass_crit, gas_const, ): """This function sets the parameters that are required for a Helmholtz equation of state parameter block, and ensures that all required parameters are set. """ # Location of the *.so or *.dll file for external functions self.plib = library self.state_block_class = state_block_class self.component_list = component_list self.phase_equilibrium_idx = phase_equilibrium_idx self.phase_equilibrium_list = phase_equilibrium_list # Parameters, these should match what's in the C code self.temperature_crit = temperature_crit self.pressure_crit = pressure_crit self.dens_mass_crit = dens_mass_crit self.gas_const = gas_const self.mw = mw def build(self): super().build() # Location of the *.so or *.dll file for external functions # Phase list self.available = _available(self.plib) self.private_phase_list = Set(initialize=["Vap", "Liq"]) if self.config.phase_presentation == PhaseType.MIX: self.phase_list = Set(initialize=["Mix"]) elif self.config.phase_presentation == PhaseType.LG: self.phase_list = Set(initialize=["Vap", "Liq"]) elif self.config.phase_presentation == PhaseType.L: self.phase_list = Set(initialize=["Liq"]) elif self.config.phase_presentation == PhaseType.G: self.phase_list = Set(initialize=["Vap"]) # State var set self.state_vars = self.config.state_vars self.smoothing_pressure_over = Param( mutable=True, initialize=1e-4, doc="Smooth max parameter (pressure over)" ) self.smoothing_pressure_under = Param( mutable=True, initialize=1e-4, doc="Smooth max parameter (pressure under)" ) @classmethod def define_metadata(cls, obj): obj.add_properties( { "temperature_crit": {"method": None, "units": "K"}, "pressure_crit": {"method": None, "units": "Pa"}, "dens_mass_crit": {"method": None, "units": "kg/m^3"}, "gas_const": {"method": None, "units": "J/mol.K"}, "mw": {"method": None, "units": "kg/mol"}, "temperature_sat": {"method": "None", "units": "K"}, "flow_mol": {"method": None, "units": "mol/s"}, "flow_mass": {"method": None, "units": "kg/s"}, "flow_vol": {"method": None, "units": "m^3/s"}, "temperature": {"method": None, "units": "K"}, "pressure": {"method": None, "units": "Pa"}, "vapor_frac": {"method": None, "units": None}, "dens_mass_phase": {"method": None, "units": "kg/m^3"}, "temperature_red": {"method": None, "units": None}, "pressure_sat": {"method": None, "units": "kPa"}, "energy_internal_mol_phase": {"method": None, "units": "J/mol"}, "enth_mol_phase": {"method": None, "units": "J/mol"}, "entr_mol_phase": {"method": None, "units": "J/mol.K"}, "cp_mol_phase": {"method": None, "units": "J/mol.K"}, "cv_mol_phase": {"method": None, "units": "J/mol.K"}, "speed_sound_phase": {"method": None, "units": "m/s"}, "dens_mol_phase": {"method": None, "units": "mol/m^3"}, "therm_cond_phase": {"method": None, "units": "W/m.K"}, "visc_d_phase": {"method": None, "units": "Pa.s"}, "visc_k_phase": {"method": None, "units": "m^2/s"}, "phase_frac": {"method": None, "units": None}, "flow_mol_comp": {"method": None, "units": "mol/s"}, "energy_internal_mol": {"method": None, "units": "J/mol"}, "enth_mol": {"method": None, "units": "J/mol"}, "entr_mol": {"method": None, "units": "J/mol.K"}, "cp_mol": {"method": None, "units": "J/mol.K"}, "cv_mol": {"method": None, "units": "J/mol.K"}, "heat_capacity_ratio": {"method": None, "units": None}, "dens_mass": {"method": None, "units": "kg/m^3"}, "dens_mol": {"method": None, "units": "mol/m^3"}, "dh_vap_mol": {"method": None, "units": "J/mol"}, } ) obj.add_default_units( { "time": "s", "length": "m", "mass": "kg", "amount": "mol", "temperature": "K", "energy": "J", "holdup": "mol", } )
class PropParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): """ Callable method for Block construction. """ super(PropParameterData, self).build() self._state_block_class = PropStateBlock # phases self.Liq = LiquidPhase() # components self.H2O = Solvent() self.Na = Solute() self.Ca = Solute() self.Mg = Solute() self.SO4 = Solute() self.Cl = Solute() # molecular weight mw_comp_data = { "H2O": 18.015e-3, "Na": 22.990e-3, "Ca": 40.078e-3, "Mg": 24.305e-3, "SO4": 96.06e-3, "Cl": 35.453e-3, } self.mw_comp = Param( self.component_list, mutable=False, initialize=extract_data(mw_comp_data), units=pyunits.kg / pyunits.mol, doc="Molecular weight", ) self.dens_mass = Param( mutable=False, initialize=1000, units=pyunits.kg / pyunits.m**3, doc="Density", ) self.cp = Param(mutable=False, initialize=4.2e3, units=pyunits.J / (pyunits.kg * pyunits.K)) # ---default scaling--- self.set_default_scaling("temperature", 1e-2) self.set_default_scaling("pressure", 1e-6) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ "flow_mass_phase_comp": { "method": None }, "temperature": { "method": None }, "pressure": { "method": None }, "mass_frac_phase_comp": { "method": "_mass_frac_phase_comp" }, "flow_vol": { "method": "_flow_vol" }, "flow_mol_phase_comp": { "method": "_flow_mol_phase_comp" }, "conc_mol_phase_comp": { "method": "_conc_mol_phase_comp" }, "enth_flow": { "method": "_enth_flow" }, }) obj.add_default_units({ "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, })
class DSPMDEParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() CONFIG.declare("solute_list", ConfigValue( domain=list, description="List of solute species names")) CONFIG.declare("stokes_radius_data", ConfigValue( default={}, domain=dict, description="Dict of solute species names and Stokes radius data")) CONFIG.declare("diffusivity_data", ConfigValue( default={}, domain=dict, description="Dict of solute species names and bulk ion diffusivity data")) CONFIG.declare("mw_data", ConfigValue( default={}, domain=dict, description="Dict of component names and molecular weight data")) CONFIG.declare("charge", ConfigValue( default={}, domain=dict, description="Ion charge")) CONFIG.declare("activity_coefficient_model", ConfigValue( default=ActivityCoefficientModel.ideal, domain=In(ActivityCoefficientModel), description="Activity coefficient model construction flag", doc=""" Options to account for activity coefficient model. **default** - ``ActivityCoefficientModel.ideal`` .. csv-table:: :header: "Configuration Options", "Description" "``ActivityCoefficientModel.ideal``", "Activity coefficients equal to 1 assuming ideal solution" "``ActivityCoefficientModel.davies``", "Activity coefficients estimated via Davies model" """)) def build(self): ''' Callable method for Block construction. ''' super(DSPMDEParameterData, self).build() self._state_block_class = DSPMDEStateBlock # components self.H2O = Solvent() for j in self.config.solute_list: self.add_component(str(j), Solute()) # phases self.Liq = LiquidPhase() # reference # Todo: enter any relevant references # TODO: consider turning parameters into variables for future param estimation # molecular weight self.mw_comp = Param( self.component_list, mutable=True, default=18e-3, initialize=self.config.mw_data, units=pyunits.kg/pyunits.mol, doc="Molecular weight") # Stokes radius self.radius_stokes_comp = Param( self.solute_set, mutable=True, default=1e-10, initialize=self.config.stokes_radius_data, units=pyunits.m, doc="Stokes radius of solute") self.diffus_phase_comp = Param( self.phase_list, self.solute_set, mutable=True, default=1e-9, initialize=self.config.diffusivity_data, units=pyunits.m ** 2 * pyunits.s ** -1, doc="Bulk diffusivity of ion") self.visc_d_phase = Param( self.phase_list, mutable=True, default=1e-3, initialize=1e-3, #TODO:revisit- assuming ~ 1e-3 Pa*s for pure water units=pyunits.Pa * pyunits.s, doc="Fluid viscosity") # Ion charge self.charge_comp = Param( self.solute_set, mutable=True, default=1, initialize=self.config.charge, units=pyunits.dimensionless, doc="Ion charge") # Dielectric constant of water self.dielectric_constant = Param( mutable=True, default=80.4, initialize=80.4, #todo: make a variable with parameter values for coefficients in the function of temperature units=pyunits.dimensionless, doc="Dielectric constant of water") # ---default scaling--- self.set_default_scaling('temperature', 1e-2) self.set_default_scaling('pressure', 1e-6) self.set_default_scaling('dens_mass_phase', 1e-3, index='Liq') self.set_default_scaling('visc_d_phase', 1e3, index='Liq') @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties( {'flow_mol_phase_comp': {'method': None}, 'temperature': {'method': None}, 'pressure': {'method': None}, 'flow_mass_phase_comp': {'method': '_flow_mass_phase_comp'}, 'mass_frac_phase_comp': {'method': '_mass_frac_phase_comp'}, 'dens_mass_phase': {'method': '_dens_mass_phase'}, 'flow_vol_phase': {'method': '_flow_vol_phase'}, 'flow_vol': {'method': '_flow_vol'}, 'conc_mol_phase_comp': {'method': '_conc_mol_phase_comp'}, 'conc_mass_phase_comp': {'method': '_conc_mass_phase_comp'}, 'mole_frac_phase_comp': {'method': '_mole_frac_phase_comp'}, 'molality_comp': {'method': '_molality_comp'}, 'diffus_phase_comp': {'method': '_diffus_phase_comp'}, 'visc_d_phase': {'method': '_visc_d_phase'}, 'pressure_osm': {'method': '_pressure_osm'}, 'radius_stokes_comp': {'method': '_radius_stokes_comp'}, 'mw_comp': {'method': '_mw_comp'}, 'charge_comp': {'method': '_charge_comp'}, 'act_coeff_phase_comp': {'method': '_act_coeff_phase_comp'}, 'dielectric_constant': {'method': '_dielectric_constant'} }) obj.add_default_units({'time': pyunits.s, 'length': pyunits.m, 'mass': pyunits.kg, 'amount': pyunits.mol, 'temperature': pyunits.K})
class HDAParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): ''' Callable method for Block construction. ''' super(HDAParameterData, self).build() self.state_block_class = IdealStateBlock self.component_list = Set( initialize=['benzene', 'toluene', 'hydrogen', 'methane']) self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True) # List of components in each phase (optional) self.phase_comp = { "Liq": self.component_list, "Vap": self.component_list } # List of phase equilibrium index self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4, 5]) self.phase_equilibrium_list = \ {1: ["benzene", ("Vap", "Liq")], 2: ["toluene", ("Vap", "Liq")], 3: ["hydrogen", ("Vap", "Liq")], 4: ["methane", ("Vap", "Liq")], 5: ["diphenyl", ("Vap", "Liq")]} # Thermodynamic reference state self.pressure_ref = Param(mutable=True, default=101325, doc='Reference pressure [Pa]') self.temperature_ref = Param(mutable=True, default=298.15, doc='Reference temperature [K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid pressure_crit_data = { 'benzene': 48.9e5, 'toluene': 41e5, 'hydrogen': 12.9e5, 'methane': 46e5, 'diphenyl': 38.5e5 } self.pressure_crit = Param(self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(pressure_crit_data), doc='Critical pressure [Pa]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid temperature_crit_data = { 'benzene': 562.2, 'toluene': 591.8, 'hydrogen': 33.0, 'methane': 190.4, 'diphenyl': 789 } self.temperature_crit = Param( self.component_list, within=NonNegativeReals, mutable=False, initialize=extract_data(temperature_crit_data), doc='Critical temperature [K]') # Gas Constant self.gas_const = Param(within=NonNegativeReals, mutable=False, default=8.314, doc='Gas Constant [J/mol.K]') # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid mw_comp_data = { 'benzene': 78.1136E-3, 'toluene': 92.1405E-3, 'hydrogen': 2.016e-3, 'methane': 16.043e-3, 'diphenyl': 154.212e-4 } self.mw_comp = Param(self.component_list, mutable=False, initialize=extract_data(mw_comp_data), doc="molecular weight Kg/mol") # Constants for liquid densities # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) dens_liq_data = { ('benzene', '1'): 1.0162, ('benzene', '2'): 0.2655, ('benzene', '3'): 562.16, ('benzene', '4'): 0.28212, ('toluene', '1'): 0.8488, ('toluene', '2'): 0.26655, ('toluene', '3'): 591.8, ('toluene', '4'): 0.2878, ('hydrogen', '1'): 5.414, ('hydrogen', '2'): 0.34893, ('hydrogen', '3'): 33.19, ('hydrogen', '4'): 0.2706, ('methane', '1'): 2.9214, ('methane', '2'): 0.28976, ('methane', '3'): 190.56, ('methane', '4'): 0.28881, ('diphenyl', '1'): 0.5039, ('diphenyl', '2'): 0.25273, ('diphenyl', '3'): 789.26, ('diphenyl', '4'): 0.281 } self.dens_liq_params = Param( self.component_list, ['1', '2', '3', '4'], mutable=False, initialize=extract_data(dens_liq_data), doc="Parameters to compute liquid densities") # Boiling point at standard pressure # Source: Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) bp_data = { ('benzene'): 353.25, ('toluene'): 383.95, ('hydrogen'): 20.45, ('methane'): 111.75, ('diphenyl'): 528.05 } self.temperature_boil = Param( self.component_list, mutable=False, initialize=extract_data(bp_data), doc="Pure component boiling points at standard pressure [K]") # Constants for specific heat capacity, enthalpy # Sources: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid # Perry's Chemical Engineers Handbook # - Robert H. Perry (Cp_liq) cp_ig_data = { ('Liq', 'benzene', '1'): 1.29E5, ('Liq', 'benzene', '2'): -1.7E2, ('Liq', 'benzene', '3'): 6.48E-1, ('Liq', 'benzene', '4'): 0, ('Liq', 'benzene', '5'): 0, ('Vap', 'benzene', '1'): -3.392E1, ('Vap', 'benzene', '2'): 4.739E-1, ('Vap', 'benzene', '3'): -3.017E-4, ('Vap', 'benzene', '4'): 7.130E-8, ('Vap', 'benzene', '5'): 0, ('Liq', 'toluene', '1'): 1.40E5, ('Liq', 'toluene', '2'): -1.52E2, ('Liq', 'toluene', '3'): 6.95E-1, ('Liq', 'toluene', '4'): 0, ('Liq', 'toluene', '5'): 0, ('Vap', 'toluene', '1'): -2.435E1, ('Vap', 'toluene', '2'): 5.125E-1, ('Vap', 'toluene', '3'): -2.765E-4, ('Vap', 'toluene', '4'): 4.911E-8, ('Vap', 'toluene', '5'): 0, ('Liq', 'hydrogen', '1'): 0, # 6.6653e1, ('Liq', 'hydrogen', '2'): 0, # 6.7659e3, ('Liq', 'hydrogen', '3'): 0, # -1.2363e2, ('Liq', 'hydrogen', '4'): 0, # 4.7827e2, # Eqn 2 ('Liq', 'hydrogen', '5'): 0, ('Vap', 'hydrogen', '1'): 2.714e1, ('Vap', 'hydrogen', '2'): 9.274e-3, ('Vap', 'hydrogen', '3'): -1.381e-5, ('Vap', 'hydrogen', '4'): 7.645e-9, ('Vap', 'hydrogen', '5'): 0, ('Liq', 'methane', '1'): 0, # 6.5708e1, ('Liq', 'methane', '2'): 0, # 3.8883e4, ('Liq', 'methane', '3'): 0, # -2.5795e2, ('Liq', 'methane', '4'): 0, # 6.1407e2, # Eqn 2 ('Liq', 'methane', '5'): 0, ('Vap', 'methane', '1'): 1.925e1, ('Vap', 'methane', '2'): 5.213e-2, ('Vap', 'methane', '3'): 1.197e-5, ('Vap', 'methane', '4'): -1.132e-8, ('Vap', 'methane', '5'): 0, ('Liq', 'diphenyl', '1'): 1.2177e5, ('Liq', 'diphenyl', '2'): 4.2930e2, ('Liq', 'diphenyl', '3'): 0, ('Liq', 'diphenyl', '4'): 0, ('Liq', 'diphenyl', '5'): 0, ('Vap', 'diphenyl', '1'): -9.707e1, ('Vap', 'diphenyl', '2'): 1.106e0, ('Vap', 'diphenyl', '3'): -8.855e-4, ('Vap', 'diphenyl', '4'): 2.790e-7, ('Vap', 'diphenyl', '5'): 0 } self.cp_ig = Param(self.phase_list, self.component_list, ['1', '2', '3', '4', '5'], mutable=False, initialize=extract_data(cp_ig_data), doc="parameters to compute Cp_comp") # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid # fitted to Antoine form # H2, Methane from NIST webbook pressure_sat_coeff_data = { ('benzene', 'A'): 4.202, ('benzene', 'B'): 1322, ('benzene', 'C'): -38.56, ('toluene', 'A'): 4.216, ('toluene', 'B'): 1435, ('toluene', 'C'): -43.33, ('hydrogen', 'A'): 3.543, ('hydrogen', 'B'): 99.40, ('hydrogen', 'C'): 7.726, ('methane', 'A'): 3.990, ('methane', 'B'): 443.0, ('methane', 'C'): -0.49, ('diphenyl', 'A'): 4.345, ('diphenyl', 'B'): 1988, ('diphenyl', 'C'): -70.82 } self.pressure_sat_coeff = Param( self.component_list, ['A', 'B', 'C'], mutable=False, initialize=extract_data(pressure_sat_coeff_data), doc="parameters to compute Cp_comp") # Source: The Properties of Gases and Liquids (1987) # 4th edition, Chemical Engineering Series - Robert C. Reid dh_vap = { 'benzene': 3.387e4, 'toluene': 3.8262e4, 'hydrogen': 0, 'methane': 0, "diphenyl": 6.271e4 } self.dh_vap = Param(self.component_list, mutable=False, initialize=extract_data(dh_vap), doc="heat of vaporization") @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ 'flow_mol': { 'method': None, 'units': 'mol/s' }, 'flow_mol_phase_comp': { 'method': None, 'units': 'mol/s' }, 'mole_frac': { 'method': None, 'units': 'none' }, 'temperature': { 'method': None, 'units': 'K' }, 'pressure': { 'method': None, 'units': 'Pa' }, 'flow_mol_phase': { 'method': None, 'units': 'mol/s' }, 'dens_mol_phase': { 'method': '_dens_mol_phase', 'units': 'mol/m^3' }, 'pressure_sat': { 'method': '_pressure_sat', 'units': 'Pa' }, 'mole_frac_phase': { 'method': '_mole_frac_phase', 'units': 'no unit' }, 'enth_mol_phase_comp': { 'method': '_enth_mol_phase_comp', 'units': 'J/mol' }, 'enth_mol_phase': { 'method': '_enth_mol_phase', 'units': 'J/mol' }, 'entr_mol_phase_comp': { 'method': '_entr_mol_phase_comp', 'units': 'J/mol' }, 'entr_mol_phase': { 'method': '_entr_mol_phase', 'units': 'J/mol' }, 'temperature_bubble': { 'method': '_temperature_bubble', 'units': 'K' }, 'temperature_dew': { 'method': '_temperature_dew', 'units': 'K' }, 'pressure_bubble': { 'method': '_pressure_bubble', 'units': 'Pa' }, 'pressure_dew': { 'method': '_pressure_dew', 'units': 'Pa' }, 'fug_vap': { 'method': '_fug_vap', 'units': 'Pa' }, 'fug_liq': { 'method': '_fug_liq', 'units': 'Pa' }, 'dh_vap': { 'method': '_dh_vap', 'units': 'J/mol' }, 'ds_vap': { 'method': '_ds_vap', 'units': 'J/mol.K' } }) obj.add_default_units({ 'time': 's', 'length': 'm', 'mass': 'g', 'amount': 'mol', 'temperature': 'K', 'energy': 'J', 'holdup': 'mol' })
class CoagulationParameterData(PhysicalParameterBlock): CONFIG = PhysicalParameterBlock.CONFIG() def build(self): """ Callable method for Block construction. """ super(CoagulationParameterData, self).build() self._state_block_class = CoagulationStateBlock # phases self.Liq = LiquidPhase() # components self.H2O = Component() self.TSS = Component() self.TDS = Component() self.Sludge = Component() # heat capacity of liquid self.cp = Param(mutable=False, initialize=4184, units=pyunits.J / (pyunits.kg * pyunits.K)) # reference density of liquid self.ref_dens_liq = Param( domain=Reals, initialize=999.26, mutable=True, units=pyunits.kg / pyunits.m**3, doc="Reference water mass density parameter @ 0 oC and no salts", ) # change in liquid density with increasing mass fraction of salts/solids self.dens_slope = Param( domain=Reals, initialize=879.04, mutable=True, units=pyunits.kg / pyunits.m**3, doc= "Relative increase in liquid density with mass fraction of salts", ) # adjustment parameters for density change with temperature # Density calculation as a function of temperature and pressure # -------------------------------------------------------------- # Engineering Toolbox. Water - Density, Specific Weight, and # Thermal Expansion Coefficients. (2003) https://www.engineeringtoolbox.com/ # water-density-specific-weight-d_595.html [Accessed 02-01-2022] self.dens_param_A = Param( domain=Reals, initialize=-2.9335e-6, mutable=True, units=pyunits.K**-2, doc="Density correction parameter A for temperature variation", ) self.dens_param_B = Param( domain=Reals, initialize=0.001529811, mutable=True, units=pyunits.K**-1, doc="Density correction parameter B for temperature variation", ) self.dens_param_C = Param( domain=Reals, initialize=0.787973, mutable=True, units=pyunits.dimensionless, doc="Density correction parameter C for temperature variation", ) # Correction factors for changes in density with changes in pressure self.ref_pressure_correction = Param( domain=Reals, initialize=1.0135, mutable=True, units=pyunits.dimensionless, doc= "Density reference correction parameter for changes in pressure", ) self.ref_pressure_slope = Param( domain=Reals, initialize=4.9582e-10, mutable=True, units=pyunits.Pa**-1, doc="Slope of density change as a function of pressure", ) # Adjustment for dynamic viscosity as a function of temperature # ------------------------------------------------------------- # D.S. Viswananth, G. Natarajan. Data Book on the Viscosity of # Liquids. Hemisphere Publishing Corp. (1989) self.mu_A = Param( domain=Reals, initialize=2.939e-5, mutable=True, units=pyunits.kg / pyunits.m / pyunits.s, doc="Pre-exponential factor for viscosity calculation", ) self.mu_B = Param( domain=Reals, initialize=507.88, mutable=True, units=pyunits.K, doc="Exponential numerator term for viscosity calculation", ) self.mu_C = Param( domain=Reals, initialize=149.3, mutable=True, units=pyunits.K, doc="Exponential denominator term for viscosity calculation", ) # ---default scaling--- self.set_default_scaling("temperature", 1e-2) self.set_default_scaling("pressure", 1e-6) @classmethod def define_metadata(cls, obj): """Define properties supported and units.""" obj.add_properties({ "flow_mass_phase_comp": { "method": None }, "temperature": { "method": None }, "pressure": { "method": None }, "mass_frac_phase_comp": { "method": "_mass_frac_phase_comp" }, "dens_mass_phase": { "method": "_dens_mass_phase" }, "flow_vol_phase": { "method": "_flow_vol_phase" }, "conc_mass_phase_comp": { "method": "_conc_mass_phase_comp" }, "visc_d": { "method": "_visc_d" }, "enth_flow": { "method": "_enth_flow" }, }) obj.add_default_units({ "time": pyunits.s, "length": pyunits.m, "mass": pyunits.kg, "amount": pyunits.mol, "temperature": pyunits.K, })