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 test_smooth_min(simple_model): # Test that smooth_min gives correct values assert safe_log(4) == pytest.approx(1.386294, abs=1e-4) assert safe_log(0) < -5 assert safe_log(-4) < -5 assert value(safe_log(simple_model.a, simple_model.e)) == \ pytest.approx(1.386294, abs=1e-4)
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 _log_fug_coeff_method(A, b, bm, B, delta, Z, cubic_type): u = EoS_param[cubic_type]['u'] w = EoS_param[cubic_type]['w'] p = sqrt(u**2 - 4 * w) return ((b / bm * (Z - 1) * (B * p) - safe_log(Z - B, eps=1e-6) * (B * p) + A * (b / bm - delta) * safe_log( (2 * Z + B * (u + p)) / (2 * Z + B * (u - p)), eps=1e-6)) / (B * p))
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 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 return_expression(b, rblock, r_idx, T): e = None if hasattr(b.params, "_electrolyte") and b.params._electrolyte: pc_set = b.params.true_phase_component_set else: pc_set = b.phase_component_set # Get reaction orders and construct power law expression for p, j in pc_set: o = rblock.reaction_order[p, j] if e is None and o != 0: # Need to strip units from concentration term (if applicable) c = get_concentration_term(b, r_idx)[p, j] u = pyunits.get_units(c) if u is not None: # Has units, so divide conc by units expr = c / u else: # Units is None, so just use conc expr = c e = o * safe_log(expr, eps=rblock.eps) elif e is not None and o != 0: # Need to strip units from concentration term (if applicable) c = get_concentration_term(b, r_idx)[p, j] u = pyunits.get_units(c) if u is not None: # Has units, so divide conc by units expr = c / u else: # Units is None, so just use conc expr = c e = e + o * safe_log(expr, eps=rblock.eps) # Need to check units on k_eq as well u = pyunits.get_units(b.k_eq[r_idx]) if u is not None: # Has units, so divide k_eq by units expr = b.k_eq[r_idx] / u else: # Units is None, so just use k_eq expr = b.k_eq[r_idx] return safe_log(expr, eps=rblock.eps) == e
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 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 energy_internal_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] 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 # Departure function for U is similar to H minus the RT(Z-1) term return (((blk.temperature * dam_dT - am) * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=eps_SL)) / (bm * EoS_p) + sum(blk.mole_frac_phase_comp[p, j] * EoSBase.energy_internal_mol_ig_comp_pure(blk, j) for j in blk.components_in_phase(p)))
def energy_internal_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 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 # Departure function for U is similar to H minus the RT(Z-1) term return (((blk.temperature * dadT - am) * safe_log( (2 * Z + B * (EoS_u + EoS_p)) / (2 * Z + B * (EoS_u - EoS_p)), eps=1e-6)) / (bm * EoS_p) + EoSBase.energy_internal_mol_ig_comp_pure(blk, j))
def cp_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] d2am_dT2 = getattr(blk, cname + "_d2am_dT2")[p] T = blk.temperature R = Cubic.gas_constant(blk) Z = blk.compress_fact_phase[p] dZdT = _dZ_dT(blk, 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) expression1 = 2 * Z + (EoS_u + EoS_p) * B expression2 = 2 * Z + (EoS_u - EoS_p) * B expression3 = B * (dZdT + Z / T) / (Z**2 + Z * EoS_u * B + EoS_w * B**2) cp_ideal_gas = sum( blk.mole_frac_phase_comp[p, j] * get_method(blk, "cp_mol_ig_comp", j)(blk, cobj(blk, j), T) for j in blk.components_in_phase(p)) # Derived from the relations in Chapter 6 of [1] cp_departure = ( R * (T * dZdT + Z - 1) + (T * d2am_dT2 / (EoS_p * bm)) * safe_log(expression1 / expression2, eps=eps_SL) + ((am - T * dam_dT) * expression3 / bm)) return cp_ideal_gas + cp_departure
def test_log_power_law_equil_with_order(): m = ConcreteModel() # # Add a test thermo package for validation m.pparams = PhysicalParameterTestBlock() # Add a solid phase for testing m.pparams.sol = SolidPhase() m.thermo = m.pparams.build_state_block([1]) # Create a dummy reaction parameter block m.rparams = GenericReactionParameterBlock( default={ "property_package": m.pparams, "base_units": { "time": pyunits.s, "mass": pyunits.kg, "amount": pyunits.mol, "length": pyunits.m, "temperature": pyunits.K }, "equilibrium_reactions": { "r1": { "stoichiometry": { ("p1", "c1"): -1, ("p1", "c2"): 2, ("sol", "c1"): -3, ("sol", "c2"): 4 }, "equilibrium_form": log_power_law_equil, "concentration_form": ConcentrationForm.moleFraction, "parameter_data": { "reaction_order": { ("p1", "c1"): 1, ("p1", "c2"): 2, ("p2", "c1"): 3, ("p2", "c2"): 4, ("sol", "c1"): 5, ("sol", "c2"): 6 } } } } }) # Create a dummy state block m.rxn = Block([1]) add_object_reference(m.rxn[1], "phase_component_set", m.pparams._phase_component_set) add_object_reference(m.rxn[1], "params", m.rparams) add_object_reference(m.rxn[1], "state_ref", m.thermo[1]) m.rxn[1].k_eq = Var(["r1"], initialize=1) log_power_law_equil.build_parameters( m.rparams.reaction_r1, m.rparams.config.equilibrium_reactions["r1"]) # Check parameter construction assert isinstance(m.rparams.reaction_r1.reaction_order, Var) assert len(m.rparams.reaction_r1.reaction_order) == 6 assert m.rparams.reaction_r1.reaction_order["p1", "c1"].value == 1 assert m.rparams.reaction_r1.reaction_order["p1", "c2"].value == 2 assert m.rparams.reaction_r1.reaction_order["p2", "c1"].value == 3 assert m.rparams.reaction_r1.reaction_order["p2", "c2"].value == 4 assert m.rparams.reaction_r1.reaction_order["sol", "c1"].value == 5 assert m.rparams.reaction_r1.reaction_order["sol", "c2"].value == 6 assert isinstance(m.rparams.reaction_r1.eps, Param) assert m.rparams.reaction_r1.eps.value == 1e-15 # Check reaction form rform = log_power_law_equil.return_expression(m.rxn[1], m.rparams.reaction_r1, "r1", 300) assert str(rform) == str( safe_log(m.rxn[1].k_eq["r1"], eps=m.rparams.reaction_r1.eps) == m.rparams.reaction_r1.reaction_order["p1", "c1"] * safe_log(m.thermo[1].mole_frac_phase_comp["p1", "c1"], eps=m.rparams.reaction_r1.eps) + m.rparams.reaction_r1.reaction_order["p1", "c2"] * safe_log(m.thermo[1].mole_frac_phase_comp["p1", "c2"], eps=m.rparams.reaction_r1.eps) + m.rparams.reaction_r1.reaction_order["p2", "c1"] * safe_log(m.thermo[1].mole_frac_phase_comp["p2", "c1"], eps=m.rparams.reaction_r1.eps) + m.rparams.reaction_r1.reaction_order["p2", "c2"] * safe_log(m.thermo[1].mole_frac_phase_comp["p2", "c2"], eps=m.rparams.reaction_r1.eps) + m.rparams.reaction_r1.reaction_order["sol", "c1"] * safe_log(m.thermo[1].mole_frac_phase_comp["sol", "c1"], eps=m.rparams.reaction_r1.eps) + m.rparams.reaction_r1.reaction_order["sol", "c2"] * safe_log(m.thermo[1].mole_frac_phase_comp["sol", "c2"], eps=m.rparams.reaction_r1.eps))