Example #1
0
 def dens_mol_phase(b, p):
     pobj = b.params.get_phase(p)
     if pobj.is_vapor_phase() or pobj.is_liquid_phase():
         return b.pressure / (Cubic.gas_constant(b) * b.temperature *
                              b.compress_fact_phase[p])
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #2
0
    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)))
Example #3
0
def entr_mol_phase_comp(b, p, j):
    if p == "Vap":
        return get_method(b, "entr_mol_ig_comp")(b, j, b.temperature)
    elif p == "Liq":
        return get_method(b, "entr_mol_liq_comp")(b, j, b.temperature)
    else:
        raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #4
0
 def fug_phase_comp_eq(b, p, j, pp):
     pobj = b.params.get_phase(p)
     if pobj.is_vapor_phase() or pobj.is_liquid_phase():
         return (b.mole_frac_phase_comp[p, j] * b.pressure *
                 exp(_log_fug_coeff_phase_comp_eq(b, p, j, pp)))
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #5
0
    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))
Example #6
0
 def rule_boilup_ratio(self, t):
     if hasattr(self.control_volume.properties_out[t],
                "flow_mol_phase"):
         return self.boilup_ratio * \
             sum(self.control_volume.properties_out[t].
                 flow_mol_phase[p] for p in self._liquid_set) == \
             sum(self.control_volume.
                 properties_out[t].flow_mol_phase["Vap"]
                 for p in self._vapor_set)
     elif hasattr(self.control_volume.properties_out[t],
                  "flow_mol_phase_comp"):
         return self.boilup_ratio * \
             sum(self.control_volume.properties_out[t].
                 flow_mol_phase_comp[p, i]
                 for p in self._liquid_set
                 for i in self.control_volume.properties_out[t].
                 params.component_list) == \
             sum(self.control_volume.properties_out[t].
                 flow_mol_phase_comp[p, i]
                 for p in self._vapor_set
                 for i in self.control_volume.properties_out[t].
                 params.component_list)
     else:
         raise PropertyNotSupportedError(
             "Unrecognized names for flow variables encountered "
             "while building the constraint for reboiler.")
Example #7
0
 def cv_mol_phase_comp(b, p, j):
     pobj = b.params.get_phase(p)
     if pobj.is_vapor_phase():
         return EoSBase.cv_mol_ig_comp_pure(b, j)
     elif pobj.is_liquid_phase():
         return EoSBase.cv_mol_ls_comp_pure(b, j)
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #8
0
def fug_phase_comp(b, p, j):
    if p == "Vap":
        return b.mole_frac_phase_comp[p, j]*b.pressure
    elif p == "Liq":
        return b.mole_frac_phase_comp[p, j] * \
               get_method(b, "pressure_sat_comp")(b, j, b._teq)
    else:
        raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
    def _rxn_rate_conv(b, t, x, j, has_rate_reactions):
        """
        Method to determine conversion term for reaction rate terms in material
        balance equations. This method gets the basis of the material flow
        and reaction rate terms and determines the correct conversion factor.
        """
        # If rate reactions are not required, skip the rest and return 1
        if not has_rate_reactions:
            return 1

        if x is None:
            # 0D control volume
            flow_basis = b.properties_out[t].get_material_flow_basis()
            prop = b.properties_out[t]
            rxn_basis = b.reactions[t].get_reaction_rate_basis()
        else:
            # 1D control volume
            flow_basis = b.properties[t, x].get_material_flow_basis()
            prop = b.properties[t, x]
            rxn_basis = b.reactions[t, x].get_reaction_rate_basis()

        # Check for undefined basis
        if flow_basis == MaterialFlowBasis.other:
            raise ConfigurationError(
                "{} contains reaction terms, but the property package "
                "used an undefined basis (MaterialFlowBasis.other). "
                "Rate based reaction terms require the property "
                "package to define the basis of the material flow "
                "terms.".format(b.name))
        if rxn_basis == MaterialFlowBasis.other:
            raise ConfigurationError(
                "{} contains reaction terms, but the reaction package "
                "used an undefined basis (MaterialFlowBasis.other). "
                "Rate based reaction terms require the reaction "
                "package to define the basis of the reaction rate "
                "terms.".format(b.name))

        try:
            if flow_basis == rxn_basis:
                return 1
            elif (flow_basis == MaterialFlowBasis.mass
                  and rxn_basis == MaterialFlowBasis.molar):
                return prop.mw[j]
            elif (flow_basis == MaterialFlowBasis.molar
                  and rxn_basis == MaterialFlowBasis.mass):
                return 1 / prop.mw[j]
            else:
                raise BurntToast(
                    "{} encountered unrecognsied combination of bases "
                    "for reaction rate terms. Please contact the IDAES"
                    " developers with this bug.".format(b.name))
        except AttributeError:
            raise PropertyNotSupportedError(
                "{} property package does not support "
                "molecular weight (mw), which is required for "
                "using property and reaction packages with "
                "different bases.".format(b.name))
Example #10
0
def dens_mol_phase(b, p):
    if p == "Vap":
        return b.pressure/(const.gas_constant*b.temperature)
    elif p == "Liq":
        return sum(b.mole_frac_phase_comp[p, j] *
                   get_method(b, "dens_mol_liq_comp")(b, j, b.temperature)
                   for j in b.components_in_phase(p))
    else:
        raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #11
0
def _fug_phase_comp(b, p, j, T):
    pobj = b.params.get_phase(p)
    if pobj.is_vapor_phase():
        return b.mole_frac_phase_comp[p, j] * b.pressure
    elif pobj.is_liquid_phase():
        return (b.mole_frac_phase_comp[p, j] *
                get_method(b, "pressure_sat_comp", j)(b, cobj(b, j), T))
    else:
        raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #12
0
 def log_fug_phase_comp_eq(b, p, j, pp):
     pobj = b.params.get_phase(p)
     if pobj.is_vapor_phase():
         return log(b.mole_frac_phase_comp[p, j]) + log(b.pressure)
     elif pobj.is_liquid_phase():
         return (log(b.mole_frac_phase_comp[p, j]) +
                 log(get_method(b, "pressure_sat_comp", j)(
                     b, cobj(b, j), b.temperature)))
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #13
0
 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))
Example #14
0
 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))
Example #15
0
 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))
Example #16
0
 def compress_fact_phase(b, p):
     pobj = b.params.get_phase(p)
     cname = pobj._cubic_type.name
     A = getattr(b, cname + "_A")
     B = getattr(b, cname + "_B")
     f = getattr(b, "_" + cname + "_ext_func_param")
     if pobj.is_vapor_phase():
         proc = getattr(b, "_" + cname + "_proc_Z_vap")
     elif pobj.is_liquid_phase():
         proc = getattr(b, "_" + cname + "_proc_Z_liq")
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
     return proc(f, A[p], B[p])
Example #17
0
 def log_fug_phase_comp_Pbub(b, p, j, pp):
     pobj = b.params.get_phase(p)
     cobj = b.params.get_component(j)
     if pobj.is_vapor_phase():
         return (log(b._mole_frac_pbub[pp[0], pp[1], j]) +
                 log(b.pressure_bubble[pp]))
     elif pobj.is_liquid_phase():
         if (cobj.config.henry_component is not None
                 and p in cobj.config.henry_component):
             return (log(b.mole_frac_comp[j]) + log(b.henry[p, j]))
         else:
             return (log(b.mole_frac_comp[j]) + log(b.pressure_sat_comp[j]))
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #18
0
    def fug_coeff_phase_comp(blk, p, j):
        pobj = blk.params.get_phase(p)
        ctype = pobj._cubic_type

        if not (pobj.is_vapor_phase() or pobj.is_liquid_phase()):
            raise PropertyNotSupportedError(_invalid_phase_msg(blk.name, p))

        cname = pobj._cubic_type.name
        b = getattr(blk, cname + "_b")[j]
        bm = getattr(blk, cname + "_bm")[p]
        A = getattr(blk, cname + "_A")[p]
        B = getattr(blk, cname + "_B")[p]
        delta = getattr(blk, cname + "_delta")[p, j]
        Z = blk.compress_fact_phase[p]

        return exp(_log_fug_coeff_method(A, b, bm, B, delta, Z, ctype))
Example #19
0
 def log_fug_phase_comp_Tdew(b, p, j, pp):
     pobj = b.params.get_phase(p)
     cobj = b.params.get_component(j)
     if pobj.is_vapor_phase():
         return log(b.mole_frac_comp[j]) + log(b.pressure)
     elif pobj.is_liquid_phase():
         if (cobj.config.henry_component is not None and
                 p in cobj.config.henry_component):
             return (log(b._mole_frac_tdew[pp[0], pp[1], j]) +
                     log(get_method(b, "henry_component", j, p)(
                         b, p, j, b.temperature_dew[pp])))
         else:
             return (log(b._mole_frac_tdew[pp[0], pp[1], j]) +
                     log(get_method(b, "pressure_sat_comp", j)(
                             b, cobj, b.temperature_dew[pp])))
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #20
0
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))
Example #21
0
    def vol_mol_phase(b, p):
        pobj = b.params.get_phase(p)
        if pobj.is_vapor_phase():
            return Ideal.gas_constant(b)*b.temperature/b.pressure
        elif pobj.is_liquid_phase():
            ptype = "liq"
        elif pobj.is_solid_phase():
            ptype = "sol"
        else:
            raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))

        v_expr = 0
        for j in b.components_in_phase(p):
            # First try to get a method for vol_mol
            v_comp = Ideal.get_vol_mol_pure(b, ptype, j, b.temperature)
            v_expr += b.get_mole_frac()[p, j]*v_comp

        return v_expr
Example #22
0
 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))
Example #23
0
    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.henry_component is not None and
                    p in cobj(b, j).config.henry_component):
                # Use Henry's Law
                return log(b.get_mole_frac()[p, j]) + log(b.henry[p, j])
            elif cobj(b, j).config.has_vapor_pressure:
                # Use Raoult's Law
                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))
Example #24
0
    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))
Example #25
0
def _log_fug_coeff_phase_comp_eq(blk, p, j, pp):
    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
    b = getattr(blk, cname + "_b")
    bm = getattr(blk, cname + "_bm")
    Aeq = getattr(blk, "_" + cname + "_A_eq")
    Beq = getattr(blk, "_" + cname + "_B_eq")
    delta_eq = getattr(blk, "_" + cname + "_delta_eq")

    f = getattr(blk, "_" + cname + "_ext_func_param")
    if pobj.is_vapor_phase():
        proc = getattr(blk, "_" + cname + "_proc_Z_vap")
    elif pobj.is_liquid_phase():
        proc = getattr(blk, "_" + cname + "_proc_Z_liq")

    def Zeq(p):
        return proc(f, Aeq[pp, p], Beq[pp, p])

    return _log_fug_coeff_method(Aeq[pp, p], b[j], bm[p], Beq[pp, p],
                                 delta_eq[pp, p, j], Zeq(p), pobj._cubic_type)
Example #26
0
 def compress_fact_phase(b, p):
     pobj = b.params.get_phase(p)
     if pobj.is_vapor_phase() or pobj.is_liquid_phase():
         return 1
     else:
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
Example #27
0
 def log_fug_coeff_phase_comp_Pdew(b, p, j, pp):
     pobj = b.params.get_phase(p)
     if not (pobj.is_vapor_phase() or pobj.is_liquid_phase()):
         raise PropertyNotSupportedError(_invalid_phase_msg(b.name, p))
     return log(1)
Example #28
0
    def add_material_mixing_equations(self, inlet_blocks, mixed_block,
                                      mb_type):
        """
        Add material mixing equations.
        """
        pp = self.config.property_package
        # Get phase component list(s)
        pc_set = mixed_block.phase_component_set

        # Get units metadata
        units = pp.get_metadata()

        flow_basis = mixed_block[
            self.flowsheet().time.first()].get_material_flow_basis()
        if flow_basis == MaterialFlowBasis.molar:
            flow_units = units.get_derived_units("flow_mole")
        elif flow_basis == MaterialFlowBasis.mass:
            flow_units = units.get_derived_units("flow_mass")
        else:
            # Let this pass for now with no units
            flow_units = None

        if mb_type == MaterialBalanceType.componentPhase:
            # Create equilibrium generation term and constraints if required
            if self.config.has_phase_equilibrium is True:
                try:
                    self.phase_equilibrium_generation = Var(
                        self.flowsheet().time,
                        pp.phase_equilibrium_idx,
                        domain=Reals,
                        doc="Amount of generation in unit by phase equilibria",
                        units=flow_units)
                except AttributeError:
                    raise PropertyNotSupportedError(
                        "{} Property package does not contain a list of phase "
                        "equilibrium reactions (phase_equilibrium_idx), "
                        "thus does not support phase equilibrium.".format(
                            self.name))

            # Define terms to use in mixing equation
            def phase_equilibrium_term(b, t, p, j):
                if self.config.has_phase_equilibrium:
                    sd = {}
                    for r in pp.phase_equilibrium_idx:
                        if pp.phase_equilibrium_list[r][0] == j:
                            if (pp.phase_equilibrium_list[r][1][0] == p):
                                sd[r] = 1
                            elif (pp.phase_equilibrium_list[r][1][1] == p):
                                sd[r] = -1
                            else:
                                sd[r] = 0
                        else:
                            sd[r] = 0

                    return sum(b.phase_equilibrium_generation[t, r] * sd[r]
                               for r in pp.phase_equilibrium_idx)
                else:
                    return 0

            # Write phase-component balances
            @self.Constraint(
                self.flowsheet().time,
                pc_set,
                doc="Material mixing equations",
            )
            def material_mixing_equations(b, t, p, j):
                return 0 == (
                    sum(inlet_blocks[i][t].get_material_flow_terms(p, j)
                        for i in range(len(inlet_blocks))) -
                    mixed_block[t].get_material_flow_terms(p, j) +
                    phase_equilibrium_term(b, t, p, j))

        elif mb_type == MaterialBalanceType.componentTotal:
            # Write phase-component balances
            @self.Constraint(
                self.flowsheet().time,
                mixed_block.component_list,
                doc="Material mixing equations",
            )
            def material_mixing_equations(b, t, j):
                return 0 == sum(
                    sum(inlet_blocks[i][t].get_material_flow_terms(p, j)
                        for i in range(len(inlet_blocks))) -
                    mixed_block[t].get_material_flow_terms(p, j)
                    for p in mixed_block.phase_list if (p, j) in pc_set)

        elif mb_type == MaterialBalanceType.total:
            # Write phase-component balances
            @self.Constraint(self.flowsheet().time,
                             doc="Material mixing equations")
            def material_mixing_equations(b, t):
                return 0 == sum(
                    sum(
                        sum(inlet_blocks[i][t].get_material_flow_terms(p, j)
                            for i in range(len(inlet_blocks))) -
                        mixed_block[t].get_material_flow_terms(p, j)
                        for j in mixed_block.component_list
                        if (p, j) in pc_set) for p in mixed_block.phase_list)

        elif mb_type == MaterialBalanceType.elementTotal:
            raise ConfigurationError("{} Mixers do not support elemental "
                                     "material balances.".format(self.name))
        elif mb_type == MaterialBalanceType.none:
            pass
        else:
            raise BurntToast(
                "{} Mixer received unrecognised value for "
                "material_balance_type. This should not happen, "
                "please report this bug to the IDAES developers.".format(
                    self.name))
Example #29
0
    def build(self):
        """
        General build method for MixerData. This method calls a number
        of sub-methods which automate the construction of expected attributes
        of unit models.

        Inheriting models should call `super().build`.

        Args:
            None

        Returns:
            None
        """
        # Call super.build()
        super(MixerData, self).build()

        # Call setup methods from ControlVolumeBlockData
        self._get_property_package()
        self._get_indexing_sets()

        # Create list of inlet names
        inlet_list = self.create_inlet_list()

        # Build StateBlocks
        inlet_blocks = self.add_inlet_state_blocks(inlet_list)

        if self.config.mixed_state_block is None:
            mixed_block = self.add_mixed_state_block()
        else:
            mixed_block = self.get_mixed_state_block()

        mb_type = self.config.material_balance_type
        if mb_type == MaterialBalanceType.useDefault:
            t_ref = self.flowsheet().time.first()
            mb_type = mixed_block[t_ref].default_material_balance_type()

        if mb_type != MaterialBalanceType.none:
            self.add_material_mixing_equations(inlet_blocks=inlet_blocks,
                                               mixed_block=mixed_block,
                                               mb_type=mb_type)
        else:
            raise BurntToast("{} received unrecognised value for "
                             "material_mixing_type argument. This "
                             "should not occur, so please contact "
                             "the IDAES developers with this bug.".format(
                                 self.name))

        if self.config.energy_mixing_type == MixingType.extensive:
            self.add_energy_mixing_equations(inlet_blocks=inlet_blocks,
                                             mixed_block=mixed_block)
        elif self.config.energy_mixing_type == MixingType.none:
            pass
        else:
            raise ConfigurationError(
                "{} received unrecognised value for "
                "material_mixing_type argument. This "
                "should not occur, so please contact "
                "the IDAES developers with this bug.".format(self.name))

        # Add to try/expect to catch cases where pressure is not supported
        # by properties.
        try:
            if self.config.momentum_mixing_type == MomentumMixingType.minimize:
                self.add_pressure_minimization_equations(
                    inlet_blocks=inlet_blocks, mixed_block=mixed_block)
            elif (self.config.momentum_mixing_type ==
                  MomentumMixingType.equality):
                self.add_pressure_equality_equations(inlet_blocks=inlet_blocks,
                                                     mixed_block=mixed_block)
            elif (self.config.momentum_mixing_type ==
                  MomentumMixingType.minimize_and_equality):
                self.add_pressure_minimization_equations(
                    inlet_blocks=inlet_blocks, mixed_block=mixed_block)
                self.add_pressure_equality_equations(inlet_blocks=inlet_blocks,
                                                     mixed_block=mixed_block)
                self.pressure_equality_constraints.deactivate()
            elif self.config.momentum_mixing_type == MomentumMixingType.none:
                pass
            else:
                raise ConfigurationError(
                    "{} recieved unrecognised value for "
                    "momentum_mixing_type argument. This "
                    "should not occur, so please contact "
                    "the IDAES developers with this bug.".format(self.name))
        except PropertyNotSupportedError:
            raise PropertyNotSupportedError(
                "{} The property package supplied for this unit does not "
                "appear to support pressure, which is required for momentum "
                "mixing. Please set momentum_mixing_type to "
                "MomentumMixingType.none or provide a property package which "
                "supports pressure.".format(self.name))

        self.add_port_objects(inlet_list, inlet_blocks, mixed_block)
Example #30
0
    def __getattr__(self, attr):
        """
        This method is used to avoid generating unnecessary property
        calculations in state blocks. __getattr__ is called whenever a
        property is called for, and if a propery does not exist, it looks for
        a method to create the required property, and any associated
        components.

        Create a property calculation if needed. Return an attrbute error if
        attr == 'domain' or starts with a _ . The error for _ prevents a
        recursion error if trying to get a function to create a property and
        that function doesn't exist.  Pyomo also ocasionally looks for things
        that start with _ and may not exist.  Pyomo also looks for the domain
        attribute, and it may not exist.
        This works by creating a property calculation by calling the "_"+attr
        function.

        A list of __getattr__ calls is maintained in self.__getattrcalls to
        check for recursive loops which maybe useful for debugging. This list
        is cleared after __getattr__ completes successfully.

        Args:
            attr: an attribute to create and return. Should be a property
                  component.
        """
        if self._lock_attribute_creation:
            raise AttributeError(
                f"{attr} does not exist, and attribute creation is locked.")

        def clear_call_list(self, attr):
            """Local method for cleaning up call list when a call is handled.

                Args:
                    attr: attribute currently being handled
            """
            if self.__getattrcalls[-1] == attr:
                if len(self.__getattrcalls) <= 1:
                    del self.__getattrcalls
                else:
                    del self.__getattrcalls[-1]
            else:
                raise PropertyPackageError(
                    "{} Trying to remove call {} from __getattr__"
                    " call list, however this is not the most "
                    "recent call in the list ({}). This indicates"
                    " a bug in the __getattr__ calls. Please "
                    "contact the IDAES developers with this bug.".format(
                        self.name, attr, self.__getattrcalls[-1]))

        # Check that attr is not something we shouldn't touch
        if attr == "domain" or attr.startswith("_"):
            # Don't interfere with anything by getting attributes that are
            # none of my business
            raise PropertyPackageError(
                '{} {} does not exist, but is a protected '
                'attribute. Check the naming of your '
                'components to avoid any reserved names'.format(
                    self.name, attr))

        if attr == "config":
            try:
                self._get_config_args()
                return self.config
            except:
                raise BurntToast("{} getattr method was triggered by a call "
                                 "to the config block, but _get_config_args "
                                 "failed. This should never happen.")

        # Check for recursive calls
        try:
            # Check if __getattrcalls is initialized
            self.__getattrcalls
        except AttributeError:
            # Initialize it
            self.__getattrcalls = [attr]
        else:
            # Check to see if attr already appears in call list
            if attr in self.__getattrcalls:
                # If it does, indicates a recursive loop.
                if attr == self.__getattrcalls[-1]:
                    # attr method is calling itself
                    self.__getattrcalls.append(attr)
                    raise PropertyPackageError(
                        '{} _{} made a recursive call to '
                        'itself, indicating a potential '
                        'recursive loop. This is generally '
                        'caused by the {} method failing to '
                        'create the {} component.'.format(
                            self.name, attr, attr, attr))
                else:
                    self.__getattrcalls.append(attr)
                    raise PropertyPackageError(
                        '{} a potential recursive loop has been '
                        'detected whilst trying to construct {}. '
                        'A method was called, but resulted in a '
                        'subsequent call to itself, indicating a '
                        'recursive loop. This may be caused by a '
                        'method trying to access a component out '
                        'of order for some reason (e.g. it is '
                        'declared later in the same method). See '
                        'the __getattrcalls object for a list of '
                        'components called in the __getattr__ '
                        'sequence.'.format(self.name, attr))
            # If not, add call to list
            self.__getattrcalls.append(attr)

        # Get property information from properties metadata
        try:
            m = self.config.parameters.get_metadata().properties

            if m is None:
                raise PropertyPackageError(
                    '{} property package get_metadata()'
                    ' method returned None when trying to create '
                    '{}. Please contact the developer of the '
                    'property package'.format(self.name, attr))
        except KeyError:
            # If attr not in metadata, assume package does not
            # support property
            clear_call_list(self, attr)
            raise PropertyNotSupportedError(
                '{} {} is not supported by property package (property is '
                'not listed in package metadata properties).'.format(
                    self.name, attr))

        # Get method name from resulting properties
        try:
            if m[attr]['method'] is None:
                # If method is none, property should be constructed
                # by property package, so raise PropertyPackageError
                clear_call_list(self, attr)
                raise PropertyPackageError(
                    '{} {} should be constructed automatically '
                    'by property package, but is not present. '
                    'This can be caused by methods being called '
                    'out of order.'.format(self.name, attr))
            elif m[attr]['method'] is False:
                # If method is False, package does not support property
                # Raise NotImplementedError
                clear_call_list(self, attr)
                raise PropertyNotSupportedError(
                    '{} {} is not supported by property package '
                    '(property method is listed as False in '
                    'package property metadata).'.format(self.name, attr))
            elif isinstance(m[attr]['method'], str):
                # Try to get method name in from PropertyBlock object
                try:
                    f = getattr(self, m[attr]['method'])
                except AttributeError:
                    # If fails, method does not exist
                    clear_call_list(self, attr)
                    raise PropertyPackageError(
                        '{} {} package property metadata method '
                        'returned a name that does not correspond'
                        ' to any method in the property package. '
                        'Please contact the developer of the '
                        'property package.'.format(self.name, attr))
            else:
                # Otherwise method name is invalid
                clear_call_list(self, attr)
                raise PropertyPackageError(
                    '{} {} package property metadata method '
                    'returned invalid value for method name. '
                    'Please contact the developer of the '
                    'property package.'.format(self.name, attr))
        except KeyError:
            # No method key - raise Exception
            # Need to use an AttributeError so Pyomo.DAE will handle this
            clear_call_list(self, attr)
            raise PropertyNotSupportedError(
                '{} package property metadata method '
                'does not contain a method for {}. '
                'Please select a package which supports '
                'the necessary properties for your process.'.format(
                    self.name, attr))

        # Call attribute if it is callable
        # If this fails, it should return a meaningful error.
        if callable(f):
            try:
                f()
            except Exception:
                # Clear call list and reraise error
                clear_call_list(self, attr)
                raise
        else:
            # If f is not callable, inform the user and clear call list
            clear_call_list(self, attr)
            raise PropertyPackageError(
                '{} tried calling attribute {} in order to create '
                'component {}. However the method is not callable.'.format(
                    self.name, f, attr))

        # Clear call list, and return
        comp = getattr(self, attr)
        clear_call_list(self, attr)
        return comp