Example #1
0
    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()
Example #2
0
 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)
Example #3
0
 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)
Example #4
0
 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)
     )
Example #5
0
    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
Example #6
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)
Example #7
0
 def rule_t1(b):
     return _t1 == smooth_max(b.temperature,
                              b.temperature_bubble[phase_pair], eps_1)
Example #8
0
 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))
Example #9
0
 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)