def energy_internal_mol_ig_comp_pure(b, j): # Method for calculating pure component U from H for ideal gases units = b.params.get_metadata().derived_units R = pyunits.convert(const.gas_constant, to_units=units["heat_capacity_mole"]) if cobj(b, j).parent_block().config.include_enthalpy_of_formation: # First, need to determine correction between U_form and H_form # U_form = H_form - delta_n*R*T ele_comp = cobj(b, j).config.elemental_composition if ele_comp is None: raise ConfigurationError( "{} calculation of internal energy requires elemental " "composition of all species. Please set this using the " "elemental_composition argument in the component " "declaration ({}).".format(b.name, j)) delta_n = 0 for e, s in ele_comp.items(): # Check for any element which is vapor at standard state if e in ["He", "Ne", "Ar", "Kr", "Xe", "Ra"]: delta_n += -s elif e in ["F", "Cl", "H", "N", "O"]: delta_n += -s/2 # These are diatomic at standard state delta_n += 1 # One mole of gaseous compound is formed dU_form = delta_n*R*b.params.temperature_ref else: dU_form = 0 # No heat of formation to correct # For ideal gases, U = H - R(T-T_ref) + dU_form return (get_method(b, "enth_mol_ig_comp", j)( b, cobj(b, j), b.temperature) - R*(b.temperature-b.params.temperature_ref) + dU_form)
def cv_mol_ls_comp_pure(b, p, j): # Method for calculating pure component liquid and solid cv from cp # For ideal (incompressible) liquids and solids, cv = cp pobj = b.params.get_phase(p) if pobj.is_liquid_phase(): return get_method(b, "cp_mol_liq_comp", j)( b, cobj(b, j), b.temperature) elif pobj.is_solid_phase(): return get_method(b, "cp_mol_sol_comp", j)( b, cobj(b, j), b.temperature)
def enth_mol_phase_comp(b, p, j): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return get_method(b, "enth_mol_ig_comp", j)( b, cobj(b, j), b.temperature) elif pobj.is_liquid_phase(): return get_method(b, "enth_mol_liq_comp", j)( b, cobj(b, j), b.temperature) else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def rule_vol_mol_solvent(b): # Eqn 77 if len(b.params.solvent_set) == 1: s = b.params.solvent_set.first() return 1/get_method(b, "dens_mol_liq_comp", s)( b, cobj(b, s), b.temperature) else: return (sum(b.mole_frac_phase_comp_true[pname, s] / get_method(b, "dens_mol_liq_comp", s)( b, cobj(b, s), b.temperature) for s in b.params.solvent_set) / sum(b.mole_frac_phase_comp_true[pname, s] for s in b.params.solvent_set))
def _fug_phase_comp(b, p, j, T): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return b.get_mole_frac()[p, j] * b.pressure elif pobj.is_liquid_phase(): if cobj(b, j).config.has_vapor_pressure: return (b.get_mole_frac()[p, j] * get_method(b, "pressure_sat_comp", j)(b, cobj(b, j), T)) else: return Expression.Skip else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def entr_mol_phase_comp(b, p, j): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return (get_method(b, "entr_mol_ig_comp", j)(b, cobj( b, j), b.temperature) - Ideal.gas_constant(b) * log(b.mole_frac_phase_comp[p, j] * b.pressure / b.params.pressure_ref)) elif pobj.is_liquid_phase(): # Assume no pressure/volume dependecy of entropy for ideal liquids return (get_method(b, "entr_mol_liq_comp", j)(b, cobj(b, j), b.temperature)) else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def log_fug_phase_comp_eq(b, p, j, pp): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return log(b.get_mole_frac()[p, j]) + log(b.pressure) elif pobj.is_liquid_phase(): if cobj(b, j).config.has_vapor_pressure: return (log(b.get_mole_frac()[p, j]) + log( get_method(b, "pressure_sat_comp", j)(b, cobj(b, j), b.temperature))) else: return Expression.Skip else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def rule_eps_solvent(b): # Eqn 78 if len(b.params.solvent_set) == 1: s = b.params.solvent_set.first() return get_method(b, "relative_permittivity_liq_comp", s)(b, cobj(b, s), b.temperature) else: return (sum(b.mole_frac_phase_comp_true[pname, s] * get_method(b, "relative_permittivity_liq_comp", s) (b, cobj(b, s), b.temperature) * b.params.get_component(s).mw for s in b.params.solvent_set) / sum(b.mole_frac_phase_comp_true[pname, s] * b.params.get_component(s).mw for s in b.params.solvent_set))
def entr_mol_phase_comp(blk, p, j): pobj = blk.params.get_phase(p) if not (pobj.is_vapor_phase() or pobj.is_liquid_phase()): raise PropertyNotSupportedError(_invalid_phase_msg(blk.name, p)) cname = pobj._cubic_type.name bm = getattr(blk, cname + "_bm")[p] B = getattr(blk, cname + "_B")[p] dadT = getattr(blk, cname + "_dadT")[p] Z = blk.compress_fact_phase[p] EoS_u = EoS_param[pobj._cubic_type]['u'] EoS_w = EoS_param[pobj._cubic_type]['w'] EoS_p = sqrt(EoS_u**2 - 4 * EoS_w) # See pg. 102 in Properties of Gases and Liquids return (((Cubic.gas_constant(blk) * safe_log( (Z - B) / Z, eps=1e-6) * bm * EoS_p + Cubic.gas_constant(blk) * safe_log(Z * blk.params.pressure_ref / (blk.mole_frac_phase_comp[p, j] * blk.pressure), eps=1e-6) * bm * EoS_p + dadT * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=1e-6)) / (bm * EoS_p)) + get_method(blk, "entr_mol_ig_comp", j)(blk, cobj(blk, j), blk.temperature))
def enth_mol_phase(blk, p): pobj = blk.params.get_phase(p) if not (pobj.is_vapor_phase() or pobj.is_liquid_phase()): raise PropertyNotSupportedError(_invalid_phase_msg(blk.name, p)) cname = pobj._cubic_type.name am = getattr(blk, cname + "_am")[p] bm = getattr(blk, cname + "_bm")[p] B = getattr(blk, cname + "_B")[p] dadT = getattr(blk, cname + "_dadT")[p] Z = blk.compress_fact_phase[p] EoS_u = EoS_param[pobj._cubic_type]['u'] EoS_w = EoS_param[pobj._cubic_type]['w'] EoS_p = sqrt(EoS_u**2 - 4 * EoS_w) # Derived from equation on pg. 120 in Properties of Gases and Liquids return (((blk.temperature * dadT - am) * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=1e-6) + Cubic.gas_constant(blk) * blk.temperature * (Z - 1) * bm * EoS_p) / (bm * EoS_p) + sum(blk.mole_frac_phase_comp[p, j] * get_method(blk, "enth_mol_ig_comp", j) (blk, cobj(blk, j), blk.temperature) for j in blk.components_in_phase(p)))
def entr_mol_phase(blk, p): pobj = blk.params.get_phase(p) cname = pobj._cubic_type.name bm = getattr(blk, cname + "_bm")[p] B = getattr(blk, cname + "_B")[p] dam_dT = getattr(blk, cname + "_dam_dT")[p] Z = blk.compress_fact_phase[p] EoS_u = EoS_param[pobj._cubic_type]['u'] EoS_w = EoS_param[pobj._cubic_type]['w'] EoS_p = sqrt(EoS_u**2 - 4 * EoS_w) R = Cubic.gas_constant(blk) entr_ideal_gas = -R * safe_log(blk.pressure / blk.params.pressure_ref, eps=eps_SL) for j in blk.components_in_phase(p): entr_j = get_method(blk, "entr_mol_ig_comp", j)(blk, cobj(blk, j), blk.temperature) xj = blk.mole_frac_phase_comp[p, j] log_xj = blk.log_mole_frac_phase_comp[p, j] entr_ideal_gas += xj * (entr_j - R * log_xj) # See pg. 102 in Properties of Gases and Liquids # or pg. 208 of Sandler, 4th Ed. entr_departure = (R * safe_log( (Z - B), eps=eps_SL) + dam_dT / (bm * EoS_p) * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=eps_SL)) return entr_ideal_gas + entr_departure
def enth_mol_phase(blk, p): pobj = blk.params.get_phase(p) cname = pobj._cubic_type.name am = getattr(blk, cname + "_am")[p] bm = getattr(blk, cname + "_bm")[p] B = getattr(blk, cname + "_B")[p] dam_dT = getattr(blk, cname + "_dam_dT")[p] Z = blk.compress_fact_phase[p] R = Cubic.gas_constant(blk) T = blk.temperature EoS_u = EoS_param[pobj._cubic_type]['u'] EoS_w = EoS_param[pobj._cubic_type]['w'] EoS_p = sqrt(EoS_u**2 - 4 * EoS_w) enth_ideal = sum(blk.mole_frac_phase_comp[p, j] * get_method(blk, "enth_mol_ig_comp", j) (blk, cobj(blk, j), blk.temperature) for j in blk.components_in_phase(p)) # Derived from equation on pg. 120 in Properties of Gases and Liquids enth_departure = (R * T * (Z - 1) + (T * dam_dT - am) / (bm * EoS_p) * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=eps_SL)) return enth_ideal + enth_departure
def rule_vol_mol_solvent(b): # Eqn 77 return (sum(b.mole_frac_phase_comp_true[pname, s] / get_method(b, "dens_mol_liq_comp", s) (b, cobj(b, s), b.temperature) for s in molecular_set) / sum(b.mole_frac_phase_comp_true[pname, s] for s in molecular_set))
def rule_mole_frac_dew_temp(b, p1, p2, j): (l_phase, v_phase, vl_comps, henry_comps, l_only_comps, v_only_comps) = _valid_VL_component_list(b, (p1, p2)) if l_phase is None or v_phase is None: # Not a VLE pair return Constraint.Skip elif l_only_comps != []: # Non-vaporisables present, no dew point return Constraint.Skip if j in vl_comps: return (b._mole_frac_tdew[p1, p2, j] * get_method(b, "pressure_sat_comp", j)( b, cobj(b, j), b.temperature_dew[p1, p2]) == b.mole_frac_comp[j] * b.pressure) elif j in henry_comps: return (b._mole_frac_tdew[p1, p2, j] * b.params.get_component(j).config. henry_component[l_phase]["method"].return_expression( b, l_phase, j, b.temperature_dew[p1, p2]) == b.mole_frac_comp[j] * b.pressure) else: return b._mole_frac_tdew[p1, p2, j] == 0
def rule_X_ref(b, j): # Eqn 21 evaluated at reference state x = getattr(b, pname + "_x_ref") if (pname, j) not in b.params.true_phase_component_set: return Expression.Skip elif j in b.params.cation_set or j in b.params.anion_set: return (x[j] * abs(cobj(b, j).config.charge)) else: return x[j]
def rule_eps_solvent(b): # Eqn 78 return (sum( b.mole_frac_phase_comp_true[pname, s] * get_method(b, "relative_permittivity_liq_comp", s) (b, cobj(b, s), b.temperature) * b.params.get_component(s).mw for s in molecular_set) / sum(b.mole_frac_phase_comp_true[pname, s] * b.params.get_component(s).mw for s in molecular_set))
def rule_X(b, j): # Eqn 21 if (pname, j) not in b.params.true_phase_component_set: return Expression.Skip elif j in b.params.cation_set or j in b.params.anion_set: return (b.mole_frac_phase_comp_true[pname, j] * abs(cobj(b, j).config.charge)) else: return b.mole_frac_phase_comp_true[pname, j]
def cv_mol_ig_comp_pure(b, j): # Method for calculating pure component ideal gas cv from cp # For ideal gases, cv = cp - R units = b.params.get_metadata().derived_units R = pyunits.convert(const.gas_constant, to_units=units["heat_capacity_mole"]) return (get_method(b, "cp_mol_ig_comp", j)( b, cobj(b, j), b.temperature) - R)
def rule_Y(b, j): if cobj(b, j).config.charge < 0: # Anion dom = b.params.anion_set else: dom = b.params.cation_set X = getattr(b, pname + "_X") return X[j] / sum(X[i] for i in dom) # Eqns 36 and 37
def _fug_phase_comp(b, p, j, T): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return b.get_mole_frac(p)[p, j] * b.pressure elif pobj.is_liquid_phase(): if (cobj(b, j).config.henry_component is not None and p in cobj(b, j).config.henry_component): # Use Henry's Law return henry_pressure(b, p, j, T) elif cobj(b, j).config.has_vapor_pressure: # Use Raoult's Law return (b.get_mole_frac(p)[p, j] * get_method(b, "pressure_sat_comp", j)(b, cobj(b, j), T)) else: return Expression.Skip else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def enth_mol_phase(b, p): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return sum(b.get_mole_frac()[p, j]*b.enth_mol_phase_comp[p, j] for j in b.components_in_phase(p)) elif pobj.is_liquid_phase(): return (sum(b.get_mole_frac()[p, j] * get_method(b, "enth_mol_liq_comp", j)( b, cobj(b, j), b.temperature) for j in b.components_in_phase(p)) + (b.pressure-b.params.pressure_ref)/b.dens_mol_phase[p]) elif pobj.is_solid_phase(): return (sum(b.get_mole_frac()[p, j] * get_method(b, "enth_mol_sol_comp", j)( b, cobj(b, j), b.temperature) for j in b.components_in_phase(p)) + (b.pressure-b.params.pressure_ref)/b.dens_mol_phase[p]) else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def get_vol_mol_pure(b, phase, comp, temperature): try: vol_mol = get_method(b, "vol_mol_"+phase+"_comp", comp)( b, cobj(b, comp), temperature) except (AttributeError, ConfigurationError): # vol_mol not defined, try for dens_mol instead try: vol_mol = 1/get_method(b, "dens_mol_"+phase+"_comp", comp)( b, cobj(b, comp), temperature) except (AttributeError, ConfigurationError): # Does not have either vol_mol or dens_mol suffix = "_"+phase+"_comp" raise ConfigurationError( f"{b.name} does not have a method defined to use " f"when calculating molar volume and density for " f"component {comp} in phase {phase}. Each component " f"must define a method for either vol_mol{suffix} or " f"dens_mol{suffix}.") return vol_mol
def dens_mol_phase(b, p): pobj = b.params.get_phase(p) if pobj.is_vapor_phase(): return b.pressure/(Ideal.gas_constant(b)*b.temperature) elif pobj.is_liquid_phase(): return sum(b.mole_frac_phase_comp[p, j] * get_method(b, "dens_mol_liq_comp", j)( b, cobj(b, j), b.temperature) for j in b.components_in_phase(p)) else: raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
def gibbs_mol_phase_comp(blk, p, j): # Calling the enthalpy and entropy directly adds a lot of overhead # because expressions involving the derivative of the fugacity coefficient # are generated. Those terms cancel mathematically, but I suspect Pyomo # leaves them in, causing trouble. R = Cubic.gas_constant(blk) T = blk.temperature logphi_j = _log_fug_coeff_phase_comp(blk, p, j) enth_ideal_gas = get_method(blk, "enth_mol_ig_comp", j)(blk, cobj(blk, j), T) entr_ideal_gas = ( get_method(blk, "entr_mol_ig_comp", j)(blk, cobj(blk, j), T) - R * (safe_log(blk.pressure / blk.params.pressure_ref, eps=eps_SL) + blk.log_mole_frac_phase_comp[p, j])) gibbs_ideal_gas = enth_ideal_gas - T * entr_ideal_gas gibbs_departure = R * T * logphi_j return gibbs_ideal_gas + gibbs_departure
def enth_mol_phase_comp(blk, p, j): pobj = blk.params.get_phase(p) dlogphi_j_dT = _d_log_fug_coeff_dT_phase_comp(blk, p, j) enth_ideal_gas = get_method(blk, "enth_mol_ig_comp", j)(blk, cobj(blk, j), blk.temperature) enth_departure = -Cubic.gas_constant( blk) * blk.temperature**2 * dlogphi_j_dT return enth_ideal_gas + enth_departure
def rule_bubble_press(b, p1, p2): (l_phase, v_phase, vl_comps, l_only_comps, v_only_comps) = _valid_VL_component_list(b, (p1, p2)) if l_phase is None or v_phase is None: # Not a VLE pair return Constraint.Skip elif v_only_comps != []: # Non-condensables present, no bubble point return Constraint.Skip return b.pressure_bubble[p1, p2] == sum( b.mole_frac_comp[j] * get_method(b, "pressure_sat_comp", j) (b, cobj(b, j), b.temperature) for j in vl_comps)
def rule_dew_press(b, p1, p2): (l_phase, v_phase, vl_comps, l_only_comps, v_only_comps) = _valid_VL_component_list(b, (p1, p2)) if l_phase is None or v_phase is None: # Not a VLE pair return Constraint.Skip elif l_only_comps != []: # Non-vaporisables present, no dew point return Constraint.Skip return 0 == 1 - b.pressure_dew[p1, p2] * sum( b.mole_frac_comp[j] / get_method(b, "pressure_sat_comp", j) (b, cobj(b, j), b.temperature) for j in vl_comps)
def energy_internal_mol_ls_comp_pure(b, p, j): pobj = b.params.get_phase(p) if pobj.is_liquid_phase(): mthd = get_method(b, "enth_mol_liq_comp", j) elif pobj.is_solid_phase(): mthd = get_method(b, "enth_mol_sol_comp", j) # Method for calculating pure component U from H for liquids & solids units = b.params.get_metadata().derived_units R = pyunits.convert(const.gas_constant, to_units=units["heat_capacity_mole"]) if cobj(b, j).parent_block().config.include_enthalpy_of_formation: # First, need to determine correction between U_form and H_form # U_form = H_form - delta_n*R*T ele_comp = cobj(b, j).config.elemental_composition if ele_comp is None: raise ConfigurationError( "{} calculation of internal energy requires elemental " "composition of all species. Please set this using the " "elemental_composition argument in the component " "declaration ({}).".format(b.name, j)) delta_n = 0 for e, s in ele_comp.items(): # Check for any element which is vapor at standard state if e in ["He", "Ne", "Ar", "Kr", "Xe", "Ra"]: delta_n += -s elif e in ["F", "Cl", "H", "N", "O"]: delta_n += -s/2 # These are diatomic at standard state dU_form = delta_n*R*b.params.temperature_ref # For ideal (incompressible) liquids and solids, U = H + dU_form return (mthd(b, cobj(b, j), b.temperature) + dU_form) else: # If not including heat of formation, U = H return mthd(b, cobj(b, j), b.temperature)
def entr_mol_phase_comp(blk, p, j): pobj = blk.params.get_phase(p) logphi_j = _log_fug_coeff_phase_comp(blk, p, j) dlogphi_j_dT = _d_log_fug_coeff_dT_phase_comp(blk, p, j) R = Cubic.gas_constant(blk) entr_ideal_gas = ( get_method(blk, "entr_mol_ig_comp", j)(blk, cobj(blk, j), blk.temperature) - R * (safe_log(blk.pressure / blk.params.pressure_ref, eps=eps_SL) + blk.log_mole_frac_phase_comp[p, j])) entr_departure = -R * logphi_j - R * blk.temperature * dlogphi_j_dT return entr_ideal_gas + entr_departure
def rule_mole_frac_dew_press(b, p1, p2, j): (l_phase, v_phase, vl_comps, l_only_comps, v_only_comps) = _valid_VL_component_list(b, (p1, p2)) if l_phase is None or v_phase is None: # Not a VLE pair return Constraint.Skip elif l_only_comps != []: # Non-vaporisables present, no dew point return Constraint.Skip if j in vl_comps: return (b._mole_frac_pdew[p1, p2, j] * get_method(b, "pressure_sat_comp", j)(b, cobj( b, j), b.temperature) == b.mole_frac_comp[j] * b.pressure_dew[p1, p2]) else: return b._mole_frac_pdew[p1, p2, j] == 0