def _tpx_phase_eq(self): # Saturation pressure eps_pu = self.config.parameters.smoothing_pressure_under eps_po = self.config.parameters.smoothing_pressure_over priv_plist = self.config.parameters.private_phase_list plist = self.config.parameters.phase_list rhoc = self.config.parameters.dens_mass_crit P = self.pressure / 1000 # expression for pressure in kPa Psat = self.pressure_sat / 1000.0 # expression for Psat in kPA vf = self.vapor_frac tau = self.tau # Terms for determining if you are above, below, or at the Psat self.P_under_sat = Expression( expr=smooth_max(0, Psat - P, eps_pu), doc="pressure above Psat, 0 if liqid exists [kPa]", ) self.P_over_sat = Expression( expr=smooth_max(0, P - Psat, eps_po), doc="pressure below Psat, 0 if vapor exists [kPa]", ) # Calculate liquid and vapor density. If the phase doesn't exist, # density will be calculated at the saturation or critical pressure def rule_dens_mass(b, p): if p == "Liq": self.scaling_factor[self.dens_mass_phase[p]] = 1e-2 return rhoc * self.func_delta_liq(P + self.P_under_sat, tau) else: self.scaling_factor[self.dens_mass_phase[p]] = 1e1 return rhoc * self.func_delta_vap(P - self.P_over_sat, tau) self.dens_mass_phase = Expression(priv_plist, rule=rule_dens_mass) # Reduced Density (no _mass_ identifier because mass or mol is same) def rule_dens_red(b, p): return self.dens_mass_phase[p] / rhoc self.dens_phase_red = Expression( priv_plist, rule=rule_dens_red, doc="reduced density [unitless]" ) # If there is only one phase fix the vapor fraction appropriately if len(plist) == 1: if "Vap" in plist: self.vapor_frac.fix(1.0) else: self.vapor_frac.fix(0.0) elif not self.config.defined_state: self.eq_complementarity = Constraint( expr=0 == (vf * self.P_over_sat - (1 - vf) * self.P_under_sat) ) self.scaling_expression[self.eq_complementarity] = 10 / self.pressure # eq_sat can activated to force the pressure to be the saturation # pressure, if you use this constraint deactivate eq_complementarity self.eq_sat = Constraint(expr=P / 1000.0 == Psat / 1000.0) self.scaling_expression[self.eq_sat] = 1000 / self.pressure self.eq_sat.deactivate()
def output_constraint(b, t): if t == t0: return pyo.Constraint.Skip else: return self.output[t] ==\ smooth_min( smooth_max(self.unconstrained_output[t], l, e), h, e)
def rule_Cmax(blk, t): caph = (blk.hot_side.properties_in[t].flow_mol * blk.hot_side.properties_in[t].cp_mol) capc = pyunits.convert(blk.cold_side.properties_in[t].flow_mol * blk.cold_side.properties_in[t].cp_mol, to_units=hunits("power") / hunits("temperature")) return smooth_max(caph, capc, eps=blk.eps_cmin)
def steam_entering_velocity(b, t): # 1.414 = 44.72/sqrt(1000) for SI if comparing to Liese (2014), # b.delta_enth_isentropic[t] = -(hin - hiesn), the mw converts # enthalpy to a mass basis return 1.414 * sqrt(smooth_max(1e-5, (b.blade_reaction - 1)*b.delta_enth_isentropic[t]*self.eff_nozzle / b.control_volume.properties_in[0].mw, eps=1e-6) )
def return_expression(b, rblock, r_idx, T): e = None s = 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: p_obj = b.state_ref.params.get_phase(p) # First, build E o = rblock.reaction_order[p, j] if e is None and o.value != 0: e = get_concentration_term(b, r_idx)[p, j]**o elif e is not None and o.value != 0: e = e * get_concentration_term(b, r_idx)[p, j]**o if p_obj.is_solid_phase(): # If solid phase, identify S r_config = b.params.config.equilibrium_reactions[r_idx] try: stoic = r_config.stoichiometry[p, j] if s is None and stoic != 0: s = b.state_ref.flow_mol_phase_comp[p, j] elif s is not None and stoic != 0: s += b.state_ref.flow_mol_phase_comp[p, j] except KeyError: pass if s is None: # Catch for not finding a solid phase raise ConfigurationError( "{} did not find a solid phase component for precipitation " "reaction {}. This is likely due to the reaction " "configuration.".format(b.name, r_idx)) else: # Need to remove units as complementarity is not consistent sunits = pyunits.get_units(s) if sunits is not None: s = s / sunits Q = b.k_eq[r_idx] - e # Need to remove units again Qunits = pyunits.get_units(b.k_eq[r_idx]) if Qunits is not None: Q = Q / Qunits return s - smooth_max(0, s - Q, rblock.eps) == 0
def test_smooth_max(simple_model): # Test that smooth_max gives correct values assert smooth_max(3.0, 12.0) == pytest.approx(12.0, abs=1e-4) assert value(smooth_max(simple_model.a, simple_model.b, simple_model.e)) == pytest.approx(4.0, abs=1e-4)
def rule_t1(b): return _t1 == smooth_max(b.temperature, b.temperature_bubble[phase_pair], eps_1)
def inlet_pressure_eqn(b, t): return b.valve_1.control_volume.properties_in[t].pressure == \ smooth_min(600000, smooth_max(500000, 50000*(b.time_var[t] - 10) + 500000))
def rule_t1(b): return b._t1 == smooth_max(b.temperature, b.temperature_bubble, b.eps_1)
def test_solubility_product_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": solubility_product, "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) # Check parameter construction assert isinstance(m.rparams.reaction_r1.eps, Param) assert value(m.rparams.reaction_r1.eps) == 1e-4 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 # Check reaction form rform = solubility_product.return_expression(m.rxn[1], m.rparams.reaction_r1, "r1", 300) s = (m.thermo[1].flow_mol_phase_comp["sol", "c1"] + m.thermo[1].flow_mol_phase_comp["sol", "c2"]) Q = (m.rxn[1].k_eq["r1"] - (m.thermo[1].mole_frac_phase_comp["p1", "c1"]** m.rparams.reaction_r1.reaction_order["p1", "c1"] * m.thermo[1].mole_frac_phase_comp["p1", "c2"]** m.rparams.reaction_r1.reaction_order["p1", "c2"] * m.thermo[1].mole_frac_phase_comp["p2", "c1"]** m.rparams.reaction_r1.reaction_order["p2", "c1"] * m.thermo[1].mole_frac_phase_comp["p2", "c2"]** m.rparams.reaction_r1.reaction_order["p2", "c2"] * m.thermo[1].mole_frac_phase_comp["sol", "c1"]** m.rparams.reaction_r1.reaction_order["sol", "c1"] * m.thermo[1].mole_frac_phase_comp["sol", "c2"]** m.rparams.reaction_r1.reaction_order["sol", "c2"])) assert str(rform) == str( s - smooth_max(0, s - Q, m.rparams.reaction_r1.eps) == 0)