Beispiel #1
0
    def test_get_check_units_on_all_expressions(self):
        # this method is going to test all the expression types that should work
        # to be defensive, we will also test that we actually have the expected expression type
        # therefore, if the expression system changes and we get a different expression type,
        # we will know we need to change these tests

        uc = units
        kg = uc.kg
        m = uc.m

        model = ConcreteModel()
        model.x = Var()
        model.y = Var()
        model.z = Var()
        model.p = Param(initialize=42.0, mutable=True)
        model.xkg = Var(units=kg)
        model.ym = Var(units=m)

        # test equality
        self._get_check_units_ok(3.0 * kg == 1.0 * kg, uc, 'kg',
                                 EXPR.EqualityExpression)
        self._get_check_units_fail(3.0 * kg == 2.0 * m, uc,
                                   EXPR.EqualityExpression)

        # test inequality
        self._get_check_units_ok(3.0 * kg <= 1.0 * kg, uc, 'kg',
                                 EXPR.InequalityExpression)
        self._get_check_units_fail(3.0 * kg <= 2.0 * m, uc,
                                   EXPR.InequalityExpression)
        self._get_check_units_ok(3.0 * kg >= 1.0 * kg, uc, 'kg',
                                 EXPR.InequalityExpression)
        self._get_check_units_fail(3.0 * kg >= 2.0 * m, uc,
                                   EXPR.InequalityExpression)

        # test RangedExpression
        self._get_check_units_ok(inequality(3.0 * kg, 4.0 * kg, 5.0 * kg), uc,
                                 'kg', EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * m, 4.0 * kg, 5.0 * kg), uc,
                                   EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * kg, 4.0 * m, 5.0 * kg), uc,
                                   EXPR.RangedExpression)
        self._get_check_units_fail(inequality(3.0 * kg, 4.0 * kg, 5.0 * m), uc,
                                   EXPR.RangedExpression)

        # test SumExpression, NPV_SumExpression
        self._get_check_units_ok(
            3.0 * model.x * kg + 1.0 * model.y * kg + 3.65 * model.z * kg, uc,
            'kg', EXPR.SumExpression)
        self._get_check_units_fail(
            3.0 * model.x * kg + 1.0 * model.y * m + 3.65 * model.z * kg, uc,
            EXPR.SumExpression)

        self._get_check_units_ok(3.0 * kg + 1.0 * kg + 2.0 * kg, uc, 'kg',
                                 EXPR.NPV_SumExpression)
        self._get_check_units_fail(3.0 * kg + 1.0 * kg + 2.0 * m, uc,
                                   EXPR.NPV_SumExpression)

        # test ProductExpression, NPV_ProductExpression
        self._get_check_units_ok(model.x * kg * model.y * m, uc, 'kg*m',
                                 EXPR.ProductExpression)
        self._get_check_units_ok(3.0 * kg * 1.0 * m, uc, 'kg*m',
                                 EXPR.NPV_ProductExpression)
        self._get_check_units_ok(3.0 * kg * m, uc, 'kg*m',
                                 EXPR.NPV_ProductExpression)
        # I don't think that there are combinations that can "fail" for products

        # test MonomialTermExpression
        self._get_check_units_ok(model.x * kg, uc, 'kg',
                                 EXPR.MonomialTermExpression)

        # test DivisionExpression, NPV_DivisionExpression
        self._get_check_units_ok(1.0 / (model.x * kg), uc, '1/kg',
                                 EXPR.DivisionExpression)
        self._get_check_units_ok(2.0 / kg, uc, '1/kg',
                                 EXPR.NPV_DivisionExpression)
        self._get_check_units_ok((model.x * kg) / 1.0, uc, 'kg',
                                 EXPR.MonomialTermExpression)
        self._get_check_units_ok(kg / 2.0, uc, 'kg',
                                 EXPR.NPV_DivisionExpression)
        self._get_check_units_ok(model.y * m / (model.x * kg), uc, 'm/kg',
                                 EXPR.DivisionExpression)
        self._get_check_units_ok(m / kg, uc, 'm/kg',
                                 EXPR.NPV_DivisionExpression)
        # I don't think that there are combinations that can "fail" for products

        # test PowExpression, NPV_PowExpression
        # ToDo: fix the str representation to combine the powers or the expression system
        self._get_check_units_ok(
            (model.x * kg**2)**3, uc, 'kg**6',
            EXPR.PowExpression)  # would want this to be kg**6
        self._get_check_units_fail(kg**model.x, uc, EXPR.PowExpression,
                                   UnitsError)
        self._get_check_units_fail(model.x**kg, uc, EXPR.PowExpression,
                                   UnitsError)
        self._get_check_units_ok(kg**2, uc, 'kg**2', EXPR.NPV_PowExpression)
        self._get_check_units_fail(3.0**kg, uc, EXPR.NPV_PowExpression,
                                   UnitsError)

        # test NegationExpression, NPV_NegationExpression
        self._get_check_units_ok(-(kg * model.x * model.y), uc, 'kg',
                                 EXPR.NegationExpression)
        self._get_check_units_ok(-kg, uc, 'kg', EXPR.NPV_NegationExpression)
        # don't think there are combinations that fan "fail" for negation

        # test AbsExpression, NPV_AbsExpression
        self._get_check_units_ok(abs(kg * model.x), uc, 'kg',
                                 EXPR.AbsExpression)
        self._get_check_units_ok(abs(kg), uc, 'kg', EXPR.NPV_AbsExpression)
        # don't think there are combinations that fan "fail" for abs

        # test the different UnaryFunctionExpression / NPV_UnaryFunctionExpression types
        # log
        self._get_check_units_ok(log(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(log(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(log(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(log(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # log10
        self._get_check_units_ok(log10(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(log10(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(log10(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(log10(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sin
        self._get_check_units_ok(sin(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(sin(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(sin(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(sin(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(sin(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # cos
        self._get_check_units_ok(cos(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(cos(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(cos(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(cos(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(cos(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # tan
        self._get_check_units_ok(tan(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(tan(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(tan(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(tan(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(tan(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sin
        self._get_check_units_ok(sinh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(sinh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(sinh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(sinh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(sinh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # cos
        self._get_check_units_ok(cosh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(cosh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(cosh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(cosh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(cosh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # tan
        self._get_check_units_ok(tanh(3.0 * model.x * uc.radians), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(tanh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_fail(tanh(3.0 * kg * model.x * uc.kg), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(tanh(3.0 * model.p * uc.radians), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(tanh(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # asin
        self._get_check_units_ok(asin(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(asin(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(asin(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(asin(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # acos
        self._get_check_units_ok(acos(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(acos(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(acos(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(acos(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # atan
        self._get_check_units_ok(atan(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(atan(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(atan(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(atan(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # exp
        self._get_check_units_ok(exp(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(exp(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(exp(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(exp(3.0 * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # sqrt
        self._get_check_units_ok(sqrt(3.0 * model.x), uc, None,
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.x * kg**2), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.x * kg), uc, 'kg**0.5',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p), uc, None,
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p * kg**2), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_ok(sqrt(3.0 * model.p * kg), uc, 'kg**0.5',
                                 EXPR.NPV_UnaryFunctionExpression)
        # asinh
        self._get_check_units_ok(asinh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(asinh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(asinh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(asinh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # acosh
        self._get_check_units_ok(acosh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(acosh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(acosh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(acosh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # atanh
        self._get_check_units_ok(atanh(3.0 * model.x), uc, 'rad',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_fail(atanh(3.0 * kg * model.x), uc,
                                   EXPR.UnaryFunctionExpression, UnitsError)
        self._get_check_units_ok(atanh(3.0 * model.p), uc, 'rad',
                                 EXPR.NPV_UnaryFunctionExpression)
        self._get_check_units_fail(atanh(3.0 * model.p * kg), uc,
                                   EXPR.NPV_UnaryFunctionExpression,
                                   UnitsError)
        # ceil
        self._get_check_units_ok(ceil(kg * model.x), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(ceil(kg), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        # don't think there are combinations that fan "fail" for ceil
        # floor
        self._get_check_units_ok(floor(kg * model.x), uc, 'kg',
                                 EXPR.UnaryFunctionExpression)
        self._get_check_units_ok(floor(kg), uc, 'kg',
                                 EXPR.NPV_UnaryFunctionExpression)
        # don't think there are combinations that fan "fail" for floor

        # test Expr_ifExpression
        # consistent if, consistent then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg,
                         THEN=model.x * kg,
                         ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression)
        # unitless if, consistent then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.x * kg,
                         ELSE=model.y * kg), uc, 'kg', EXPR.Expr_ifExpression)
        # consistent if, unitless then/else
        self._get_check_units_ok(
            EXPR.Expr_if(IF=model.x * kg + kg >= 2.0 * kg,
                         THEN=model.x,
                         ELSE=model.x), uc, None, EXPR.Expr_ifExpression)
        # inconsistent then/else
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.x * m,
                         ELSE=model.y * kg), uc, EXPR.Expr_ifExpression)
        # inconsistent then/else NPV
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0,
                         THEN=model.p * m,
                         ELSE=model.p * kg), uc, EXPR.Expr_ifExpression)
        # inconsistent then/else NPV units only
        self._get_check_units_fail(
            EXPR.Expr_if(IF=model.x >= 2.0, THEN=m, ELSE=kg), uc,
            EXPR.Expr_ifExpression)

        # test EXPR.IndexTemplate and GetItemExpression
        model.S = Set()
        i = EXPR.IndexTemplate(model.S)
        j = EXPR.IndexTemplate(model.S)
        self._get_check_units_ok(i, uc, None, EXPR.IndexTemplate)

        model.mat = Var(model.S, model.S)
        self._get_check_units_ok(model.mat[i, j + 1], uc, None,
                                 EXPR.GetItemExpression)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef = ExternalFunction(python_callback_function)
        self._get_check_units_ok(model.ef(model.x, model.y), uc, None,
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef(1.0, 2.0), uc, None,
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef2 = ExternalFunction(python_callback_function, units=uc.kg)
        self._get_check_units_ok(model.ef2(model.x, model.y), uc, 'kg',
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef2(1.0, 2.0), uc, 'kg',
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef2(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef2(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef3 = ExternalFunction(python_callback_function,
                                     units=uc.kg,
                                     arg_units=[uc.kg, uc.m])
        self._get_check_units_fail(model.ef3(model.x, model.y), uc,
                                   EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(1.0, 2.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.x * kg, model.y), uc,
                                   EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef3(2.0 * kg, 1.0), uc,
                                   EXPR.NPV_ExternalFunctionExpression,
                                   UnitsError)
        self._get_check_units_ok(model.ef3(2.0 * kg, 1.0 * uc.m), uc, 'kg',
                                 EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.x * kg, model.y * m), uc,
                                 'kg', EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.xkg, model.ym), uc, 'kg',
                                 EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.ym, model.xkg), uc,
                                   EXPR.ExternalFunctionExpression,
                                   InconsistentUnitsError)
Beispiel #2
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`PERIODS`                                                       |
    | | *Within*: :code:`PositiveIntegers`                                    |
    |                                                                         |
    | The list of all periods being modeled. Periods must be non-negative     |
    | integers and the set is ordered.                                        |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Derived Sets                                                            |
    +=========================================================================+
    | | :code:`TMPS_IN_PRD`                                                   |
    | | *Defined over*: :code:`PERIODS`                                       |
    |                                                                         |
    | Indexed set that describes the timepoints that occur in each period.    |
    +-------------------------------------------------------------------------+
    | | :code:`NOT_FIRST_PRDS`                                                |
    | | *Within*: :code:`PERIODS`                                             |
    |                                                                         |
    | The list of periods excluding the first period. Relies on periods being |
    | ordered.                                                                |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`discount_factor`                                               |
    | | *Defined over*: :code:`PERIODS`                                       |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Determines the relative objective function weight of investment and     |
    | operational decisions made in each period (i.e. future costs can be     |
    | weighted less).                                                         |
    +-------------------------------------------------------------------------+
    | | :code:`number_years_represented`                                      |
    | | *Defined over*: :code:`PERIODS`                                       |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Accounts for the number of years that the periods is meant to           |
    | represent. Investment cost inputs in GridPath are annualized, so they   |
    | are multiplied by this parameter in the objective function.             |
    +-------------------------------------------------------------------------+
    | | :code:`hours_in_full_period`                                          |
    | | *Defined over*: :code:`PERIODS`                                       |
    | | *Within*: :code:`[8760, 8766, 8784]`                                  |
    |                                                                         |
    | The number of hours in a period. This should be 1 year                  |
    | (8760-8784 hours) even if the period represents more than 1 year!       |
    +-------------------------------------------------------------------------+
    | | :code:`period`                                                        |
    | | *Defined over*: :code:`TMPS`                                          |
    | | *Within*: :code:`PERIODS`                                             |
    |                                                                         |
    | Specifies the associated period for each timepoint.                     |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Derived Input Params                                                    |
    +=========================================================================+
    | | :code:`first_period`                                                  |
    | | *Within*: :code:`PERIODS`                                             |
    |                                                                         |
    | The first period in the model. Relies on the PERIODS set being ordered. |
    +-------------------------------------------------------------------------+
    | | :code:`prev_period`                                                   |
    | | *Defined over*: :code:`NOT_FIRST_PRDS`                                |
    | | *Within*: :code:`PERIODS`                                             |
    |                                                                         |
    | Determines the previous period for each period other than the first     |
    | period, which doesn't have a previous period.                           |
    +-------------------------------------------------------------------------+
    | | :code:`hours_in_subproblem_period`                                    |
    | | *Defined over*: :code:`PERIODS`                                       |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The number of hours in each period for the current subproblem, taking   |
    | into account the timepoints in each period-subproblem, the number of    |
    | hours in each timepoint, and their associated timepoint weights.        |
    | In capacity expansion mode with one subproblem, this should simply be   |
    | equal to :code:`hours_in_full_period`. In production simulation mode    |
    | with multiple subproblems within 1 period, this number is compared to   |
    | :code: hours_in_full_period` and used to adjust the reported            |
    | "per-period" costs. For instance, when running daily subproblems the    |
    | fixed cost in each day should be only 1/365 of the annualized fixed     |
    | cost.                                                                   |
    +-------------------------------------------------------------------------+

    """

    # Sets
    ###########################################################################

    m.PERIODS = Set(within=PositiveIntegers, ordered=True)

    # Required Input Params
    ###########################################################################

    m.discount_factor = Param(m.PERIODS, within=NonNegativeReals)

    m.number_years_represented = Param(m.PERIODS, within=NonNegativeReals)

    m.hours_in_full_period = Param(m.PERIODS, within=[8760, 8766, 8784])

    # TODO: think numbers_years_represent through and figure out appropriate
    #  documentation wording; can we have periods that are smaller than an
    #  year, considering how costs are defined ($/MW-yr)?

    m.period = Param(m.TMPS, within=m.PERIODS)

    # Derived Sets
    ###########################################################################

    m.TMPS_IN_PRD = Set(m.PERIODS,
                        initialize=lambda mod, p: list(
                            set(tmp for tmp in mod.TMPS
                                if mod.period[tmp] == p)))

    m.NOT_FIRST_PRDS = Set(within=m.PERIODS,
                           initialize=lambda mod: list(mod.PERIODS)[1:])

    # Derived Input Params
    ###########################################################################

    m.first_period = Param(within=m.PERIODS,
                           initialize=lambda mod: list(mod.PERIODS)[0])

    m.prev_period = Param(m.NOT_FIRST_PRDS,
                          within=m.PERIODS,
                          initialize=lambda mod, p: list(mod.PERIODS)[list(
                              mod.PERIODS).index(p) - 1])

    m.hours_in_subproblem_period = Param(
        m.PERIODS,
        within=NonNegativeReals,
        initialize=lambda mod, p: sum(mod.hrs_in_tmp[tmp] * mod.tmp_weight[tmp]
                                      for tmp in mod.TMPS_IN_PRD[p]))
Beispiel #3
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(ReactionParameterBlock, self).build()

        self._reaction_block_class = ReactionBlock

        # Create Phase objects
        self.Vap = VaporPhase()
        self.Sol = SolidPhase()

        # Create Component objects
        self.CH4 = Component()
        self.CO2 = Component()
        self.H2O = Component()
        self.Fe2O3 = Component()
        self.Fe3O4 = Component()
        self.Al2O3 = Component()

        # Component list subsets
        self.gas_component_list = Set(initialize=['CO2', 'H2O', 'CH4'])
        self.sol_component_list = Set(initialize=['Fe2O3', 'Fe3O4', 'Al2O3'])

        # Reaction Index
        self.rate_reaction_idx = Set(initialize=["R1"])

        # Gas Constant
        self.gas_const = Param(within=PositiveReals,
                               mutable=False,
                               default=8.314459848e-3,
                               doc='Gas Constant [kJ/mol.K]')

        # Smoothing factor
        self.eps = Param(mutable=True, default=1e-8, doc='Smoothing Factor')
        # Reaction rate scale factor
        self._scale_factor_rxn = Param(mutable=True,
                                       default=1,
                                       doc='Scale Factor for reaction eqn.'
                                       'Used to help initialization routine')

        # Reaction Stoichiometry
        self.rate_reaction_stoichiometry = {
            ("R1", "Vap", "CH4"): -1,
            ("R1", "Vap", "CO2"): 1,
            ("R1", "Vap", "H2O"): 2,
            ("R1", "Sol", "Fe2O3"): -12,
            ("R1", "Sol", "Fe3O4"): 8,
            ("R1", "Sol", "Al2O3"): 0
        }

        # Reaction stoichiometric coefficient
        self.rxn_stoich_coeff = Param(self.rate_reaction_idx,
                                      default=12,
                                      mutable=True,
                                      doc='Reaction stoichiometric'
                                      'coefficient [-]')

        # Standard Heat of Reaction - kJ/mol_rxn
        dh_rxn_dict = {"R1": 136.5843}
        self.dh_rxn = Param(self.rate_reaction_idx,
                            initialize=dh_rxn_dict,
                            doc="Heat of reaction [kJ/mol]")

        # -------------------------------------------------------------------------
        """ Reaction properties that can be estimated"""

        # Particle grain radius within OC particle
        self.grain_radius = Var(domain=Reals,
                                initialize=2.6e-7,
                                doc='Representative particle grain'
                                'radius within OC particle [m]')
        self.grain_radius.fix()

        # Molar density OC particle
        self.dens_mol_sol = Var(domain=Reals,
                                initialize=32811,
                                doc='Molar density of OC particle [mol/m^3]')
        self.dens_mol_sol.fix()

        # Available volume for reaction - from EPAT report (1-ep)'
        self.a_vol = Var(domain=Reals,
                         initialize=0.28,
                         doc='Available reaction vol. per vol. of OC')
        self.a_vol.fix()

        # Activation Energy
        self.energy_activation = Var(self.rate_reaction_idx,
                                     domain=Reals,
                                     initialize=4.9e1,
                                     doc='Activation energy [kJ/mol]')
        self.energy_activation.fix()

        # Reaction order
        self.rxn_order = Var(self.rate_reaction_idx,
                             domain=Reals,
                             initialize=1.3,
                             doc='Reaction order in gas species [-]')
        self.rxn_order.fix()

        # Pre-exponential factor
        self.k0_rxn = Var(self.rate_reaction_idx,
                          domain=Reals,
                          initialize=8e-4,
                          doc='Pre-exponential factor'
                          '[mol^(1-N_reaction)m^(3*N_reaction -2)/s]')
        self.k0_rxn.fix()
Beispiel #4
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(PhysicalParameterData, self).build()

        self.state_block_class = MethaneCombustionStateBlock

        # List of valid phases in property package
        self.phase_list = Set(initialize=['Vap'])

        # Component list - a list of component identifiers
        self.component_list = Set(
            initialize=['H2', 'N2', 'O2', 'CH4', 'CO', 'CO2', 'H2O', 'NH3'])

        # List of components in each phase (optional)
        self.phase_comp = {"Vap": self.component_list}

        # List of all chemical elements that constitute the chemical species
        self.element_list = Set(initialize=['H', 'N', 'O', 'C'])

        # Elemental composition of all species
        self.element_comp = {
            'H2': {
                'H': 2,
                'N': 0,
                'O': 0,
                'C': 0
            },
            'N2': {
                'H': 0,
                'N': 2,
                'O': 0,
                'C': 0
            },
            'O2': {
                'H': 0,
                'N': 0,
                'O': 2,
                'C': 0
            },
            'CH4': {
                'H': 4,
                'N': 0,
                'O': 0,
                'C': 1
            },
            'CO': {
                'H': 0,
                'N': 0,
                'O': 1,
                'C': 1
            },
            'CO2': {
                'H': 0,
                'N': 0,
                'O': 2,
                'C': 1
            },
            'H2O': {
                'H': 2,
                'N': 0,
                'O': 1,
                'C': 0
            },
            'NH3': {
                'H': 3,
                'N': 1,
                'O': 0,
                'C': 0
            }
        }

        # Heat capacity parameters - Shomate eqn (from NIST webbook)
        # Parameter 9 is the enthalpy at 1500K (Tref) in J/mol
        cp_param_dict = {
            ('H2', 1): 18.563083,
            ('H2', 2): 12.257357,
            ('H2', 3): -2.859786,
            ('H2', 4): 0.268238,
            ('H2', 5): 1.977990,
            ('H2', 6): -1.147438,
            ('H2', 7): 156.288133,
            ('H2', 8): 0.0,
            ('H2', 9): 36290.28,
            ('N2', 1): 19.50583,
            ('N2', 2): 19.88705,
            ('N2', 3): -8.598535,
            ('N2', 4): 1.369784,
            ('N2', 5): 0.527601,
            ('N2', 6): -4.935202,
            ('N2', 7): 212.3900,
            ('N2', 8): 0,
            ('N2', 9): 38405.02,
            ('O2', 1): 30.03235,
            ('O2', 2): 8.772972,
            ('O2', 3): -3.988133,
            ('O2', 4): 0.788313,
            ('O2', 5): -0.741599,
            ('O2', 6): -11.32468,
            ('O2', 7): 236.1663,
            ('O2', 8): 0,
            ('O2', 9): 40598.9,
            ('CH4', 1): 85.81217,
            ('CH4', 2): 11.26467,
            ('CH4', 3): -2.114146,
            ('CH4', 4): 0.138190,
            ('CH4', 5): -26.42221,
            ('CH4', 6): -153.5327,
            ('CH4', 7): 224.4143,
            ('CH4', 8): -74.87310,
            ('CH4', 9): 78142.7,
            ('CO', 1): 35.15070,
            ('CO', 2): 1.300095,
            ('CO', 3): -0.205921,
            ('CO', 4): 0.013550,
            ('CO', 5): -3.282780,
            ('CO', 6): -127.8375,
            ('CO', 7): 231.7120,
            ('CO', 8): -110.5271,
            ('CO', 9): 38852.26,
            ('CO2', 1): 58.16639,
            ('CO2', 2): 2.720074,
            ('CO2', 3): -0.492289,
            ('CO2', 4): 0.038844,
            ('CO2', 5): -6.447293,
            ('CO2', 6): -425.9186,
            ('CO2', 7): 263.6125,
            ('CO2', 8): -393.5224,
            ('CO2', 9): 61707.0,
            ('H2O', 1): 41.96426,
            ('H2O', 2): 8.622053,
            ('H2O', 3): -1.499780,
            ('H2O', 4): 0.098119,
            ('H2O', 5): -11.15764,
            ('H2O', 6): -272.1797,
            ('H2O', 7): 219.7809,
            ('H2O', 8): -241.8264,
            ('H2O', 9): 48150.13,
            ('NH3', 1): 52.02427,
            ('NH3', 2): 18.48801,
            ('NH3', 3): -3.765128,
            ('NH3', 4): 0.248541,
            ('NH3', 5): -12.45799,
            ('NH3', 6): -85.53895,
            ('NH3', 7): 223.8022,
            ('NH3', 8): -45.89806,
            ('NH3', 9): 63578.64
        }
        self.cp_params = Param(self.component_list,
                               range(1, 10),
                               mutable=False,
                               initialize=cp_param_dict,
                               doc="Shomate equation heat capacity parameters")

        # Heat of Formation
        hf_dict = {
            "CH4": -74600,
            "CO": -110530,
            "CO2": -393520,
            "H2": 0,
            "H2O": -241830,
            "N2": 0,
            "NH3": -45900,
            "O2": 0
        }
        self.enth_mol_form = Param(
            self.component_list,
            mutable=False,
            initialize=hf_dict,
            doc="Component molar heats of formation [J/mol]")

        # Gas Constant
        self.gas_const = Param(within=PositiveReals,
                               mutable=False,
                               default=8.314,
                               doc='Gas Constant [J/mol.K]')

        # Thermodynamic reference state
        self.pressure_ref = Param(within=PositiveReals,
                                  mutable=True,
                                  default=101325.0,
                                  doc='Reference pressure [Pa]')
        self.temperature_ref = Param(within=PositiveReals,
                                     mutable=True,
                                     default=1500.0,
                                     doc='Reference temperature [K]')
 def _visc_d(self):
     self.visc_d = Param(initialize=self.params.visc_d_default,
                         units=pyunits.kg / pyunits.m / pyunits.s,
                         mutable=True,
                         doc="Dynamic viscosity of solution")
Beispiel #6
0
    def build(self):
        super(Iapws95ParameterBlockData, self).build()
        self.state_block_class = Iapws95StateBlock
        # Location of the *.so or *.dll file for external functions
        self.plib = os.path.dirname(__file__)
        self.plib = os.path.join(self.plib, "iapws95.so")
        self.available = os.path.isfile(self.plib)
        # Phase list
        self.private_phase_list = Set(initialize=["Vap", "Liq"])
        self.phase_list = Set(initialize=["Mix"])
        # Component list - a list of component identifiers
        self.component_list = Set(initialize=['H2O'])
        # Parameters, these should match what's in the C code
        self.temperature_crit = Param(initialize=647.096,
                                      doc='Critical temperature [K]')
        self.pressure_crit = Param(initialize=2.2064e7,
                                   doc='Critical pressure [Pa]')
        self.dens_mass_crit = Param(initialize=322,
                                    doc='Critical density [kg/m3]')
        self.gas_const = Param(initialize=8.3144598,
                               doc='Gas Constant [J/mol/K]')
        self.mw = Param(initialize=0.01801528, doc='Molecular weight [kg/mol]')
        #Thermal conductivity parameters.
        # "Release on the IAPWS Formulation 2011 for the Thermal Conductivity of
        # Ordinary Water Substance"
        self.tc_L0 = Param(RangeSet(0, 5),
                           initialize={
                               0: 2.443221e-3,
                               1: 1.323095e-2,
                               2: 6.770357e-3,
                               3: -3.454586e-3,
                               4: 4.096266e-4
                           },
                           doc="0th order themalcondutivity paramters")

        self.tc_L1 = Param(RangeSet(0, 5),
                           RangeSet(0, 6),
                           initialize={
                               (0, 0): 1.60397357,
                               (1, 0): 2.33771842,
                               (2, 0): 2.19650529,
                               (3, 0): -1.21051378,
                               (4, 0): -2.7203370,
                               (0, 1): -0.646013523,
                               (1, 1): -2.78843778,
                               (2, 1): -4.54580785,
                               (3, 1): 1.60812989,
                               (4, 1): 4.57586331,
                               (0, 2): 0.111443906,
                               (1, 2): 1.53616167,
                               (2, 2): 3.55777244,
                               (3, 2): -0.621178141,
                               (4, 2): -3.18369245,
                               (0, 3): 0.102997357,
                               (1, 3): -0.463045512,
                               (2, 3): -1.40944978,
                               (3, 3): 0.0716373224,
                               (4, 3): 1.1168348,
                               (0, 4): -0.0504123634,
                               (1, 4): 0.0832827019,
                               (2, 4): 0.275418278,
                               (3, 4): 0.0,
                               (4, 4): -0.19268305,
                               (0, 5): 0.00609859258,
                               (1, 5): -0.00719201245,
                               (2, 5): -0.0205938816,
                               (3, 5): 0.0,
                               (4, 5): 0.012913842
                           },
                           doc="1st order themalcondutivity paramters")
        #Viscosity paramters
        #"Release on the IAPWS Formulation 2008 for the Viscosity of
        # Ordinary Water Substance "
        self.visc_H0 = Param(RangeSet(0, 4),
                             initialize={
                                 0: 1.67752,
                                 1: 2.20462,
                                 2: 0.6366564,
                                 3: -0.241605
                             },
                             doc="0th order viscosity parameters")

        self.visc_H1 = Param(RangeSet(0, 6),
                             RangeSet(0, 7),
                             initialize={
                                 (0, 0): 5.20094e-1,
                                 (1, 0): 8.50895e-2,
                                 (2, 0): -1.08374,
                                 (3, 0): -2.89555e-1,
                                 (4, 0): 0.0,
                                 (5, 0): 0.0,
                                 (0, 1): 2.22531e-1,
                                 (1, 1): 9.99115e-1,
                                 (2, 1): 1.88797,
                                 (3, 1): 1.26613,
                                 (4, 1): 0.0,
                                 (5, 1): 1.20573e-1,
                                 (0, 2): -2.81378e-1,
                                 (1, 2): -9.06851e-1,
                                 (2, 2): -7.72479e-1,
                                 (3, 2): -4.89837e-1,
                                 (4, 2): -2.57040e-1,
                                 (5, 2): 0.0,
                                 (0, 3): 1.61913e-1,
                                 (1, 3): 2.57399e-1,
                                 (2, 3): 0.0,
                                 (3, 3): 0.0,
                                 (4, 3): 0.0,
                                 (5, 3): 0.0,
                                 (0, 4): -3.25372e-2,
                                 (1, 4): 0.0,
                                 (2, 4): 0.0,
                                 (3, 4): 6.98452e-2,
                                 (4, 4): 0.0,
                                 (5, 4): 0.0,
                                 (0, 5): 0.0,
                                 (1, 5): 0.0,
                                 (2, 5): 0.0,
                                 (3, 5): 0.0,
                                 (4, 5): 8.72102e-3,
                                 (5, 5): 0.0,
                                 (0, 6): 0.0,
                                 (1, 6): 0.0,
                                 (2, 6): 0.0,
                                 (3, 6): -4.35673e-3,
                                 (4, 6): 0.0,
                                 (5, 6): -5.93264e-4
                             },
                             doc="1st order viscosity parameters")
Beispiel #7
0
    def build(self):
        self._set_parameters(
            library=_so,
            eos_tag="swco2",
            state_block_class=SWCO2StateBlock,
            component_list=Set(initialize=["CO2"]),
            phase_equilibrium_idx=Set(initialize=[1]),
            phase_equilibrium_list={1: ["CO2", ("Vap", "Liq")]},
            mw=Param(initialize=0.0440098,
                     doc="Molecular weight [kg/mol]",
                     units=pyunits.kg / pyunits.mol),
            temperature_crit=Param(initialize=304.1282,
                                   doc="Critical temperature [K]",
                                   units=pyunits.K),
            pressure_crit=Param(initialize=7.377e6,
                                doc="Critical pressure [Pa]",
                                units=pyunits.Pa),
            dens_mass_crit=Param(initialize=467.6,
                                 doc="Critical density [kg/m3]",
                                 units=pyunits.kg / pyunits.m**3),
            specific_gas_constant=Param(
                initialize=188.9241,
                doc="CO2 Specific Gas Constant [J/kg/K]",
                units=pyunits.J / pyunits.kg / pyunits.K),
            pressure_bounds=(0.1, 1e9),
            temperature_bounds=(210, 2500),
            enthalpy_bounds=(-2e4, 1e5),
        )

        super().build()

        # Thermal conductivity parameters.
        # Vesovic et al. (1990)
        self.tc_b = Param(
            RangeSet(0, 8),
            initialize={
                0: 0.4226159,
                1: 0.6280115,
                2: -0.5387661,
                3: 0.6735941,
                4: 0,
                5: 0,
                6: -0.4362677,
                7: 0.2255388,
            },
            doc="0 density limit thermal conductivity parameters",
        )

        self.tc_c = Param(
            RangeSet(1, 6),
            initialize={
                1: 2.387869e-2,
                2: 4.350794,
                3: -10.33404,
                4: 7.981590,
                5: -1.940558,
            },
            doc="0 density limit thermal conductivity parameters",
        )

        self.tc_d_1 = Param(initialize=2.447164e-5 * self.dens_mass_crit,
                            doc="Residual thermal conductivity parameter",
                            units=pyunits.W / pyunits.K / pyunits.m)
        self.tc_d_2 = Param(initialize=8.705605e-8 * self.dens_mass_crit**2,
                            doc="Residual thermal conductivity parameter",
                            units=pyunits.W / pyunits.K / pyunits.m)
        self.tc_d_3 = Param(initialize=-6.547950e-11 * self.dens_mass_crit**3,
                            doc="Residual thermal conductivity parameter",
                            units=pyunits.W / pyunits.K / pyunits.m)
        self.tc_d_4 = Param(initialize=6.594919e-14 * self.dens_mass_crit**4,
                            doc="Residual thermal conductivity parameter",
                            units=pyunits.W / pyunits.K / pyunits.m)

        # Viscosity parameters
        # "Fenghour et al. (1998) with critial enhancment Vesovic et al. (1990)
        self.visc_a = Param(
            RangeSet(0, 5),
            initialize={
                0: 0.235156,
                1: -0.491266,
                2: 5.211155e-2,
                3: 5.347906e-2,
                4: -1.537102e-2,
            },
            doc="0 density limit viscosity parameters",
        )

        # The indexing looks a little weird here, but it's from the source
        self.visc_d_1_1 = Param(initialize=0.4071119e-8 * self.dens_mass_crit,
                                doc="Residual viscosity parameter",
                                units=pyunits.Pa * pyunits.s)
        self.visc_d_2_1 = Param(initialize=0.7198037e-10 *
                                self.dens_mass_crit**2,
                                doc="Residual viscosity parameter",
                                units=pyunits.Pa * pyunits.s)
        self.visc_d_6_4 = Param(initialize=0.2411697e-22 *
                                self.dens_mass_crit**6,
                                doc="Residual viscosity parameter",
                                units=pyunits.Pa * pyunits.s)
        self.visc_d_8_1 = Param(initialize=0.2971072e-28 *
                                self.dens_mass_crit**8,
                                doc="Residual viscosity parameter",
                                units=pyunits.Pa * pyunits.s)
        self.visc_d_8_2 = Param(initialize=-0.1627888e-28 *
                                self.dens_mass_crit**8,
                                doc="Residual viscosity parameter",
                                units=pyunits.Pa * pyunits.s)

        self.set_default_scaling("therm_cond_phase", 1e2, index="Liq")
        self.set_default_scaling("therm_cond_phase", 1e1, index="Vap")
        self.set_default_scaling("visc_d_phase", 1e5, index="Liq")
        self.set_default_scaling("visc_d_phase", 1e6, index="Vap")
        self.set_default_scaling("visc_k_phase", 1e5, index="Liq")
        self.set_default_scaling("visc_k_phase", 1e7, index="Vap")
Beispiel #8
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`DR_NEW`                                                        |
    |                                                                         |
    | The list of :code:`dr_new` projects being modeled.                      |
    +-------------------------------------------------------------------------+
    | | :code:`DR_NEW_OPR_PRDS`                                               |
    |                                                                         |
    | Two-dimensional set of all :code:`dr_new` projects and their            |
    | operational periods.                                                    |
    +-------------------------------------------------------------------------+
    | | :code:`DR_NEW_PTS`                                                    |
    |                                                                         |
    | Two-dimensional set of all :code:`dr_new` projects and their supply     |
    | curve points.                                                           |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`dr_new_min_duration`                                           |
    | | *Defined over*: :code:`DR_NEW`                                        |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's duration in hours, i.e. how many hours the load can be    |
    | shifted.                                                                |
    +-------------------------------------------------------------------------+
    | | :code:`dr_new_min_cumulative_new_build_mwh`                           |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The minimum cumulative amount of shiftable load capacity (in MWh) that  |
    | must be built for a project by a certain period.                        |
    +-------------------------------------------------------------------------+
    | | :code:`dr_new_max_cumulative_new_build_mwh`                           |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The maximum cumulative amount of shiftable load capacity (in MWh) that  |
    | must be built for a project by a certain period.                        |
    +-------------------------------------------------------------------------+
    | | :code:`dr_new_supply_curve_slope`                                     |
    | | *Defined over*: :code:`DR_NEW_PTS`                                    |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's slope for each point (section) in the piecewise linear    |
    | supply cost curve, in $ per MWh.                                        |
    +-------------------------------------------------------------------------+
    | | :code:`dr_new_supply_curve_intercept`                                 |
    | | *Defined over*: :code:`DR_NEW_PTS`                                    |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's intercept for each point (section) in the piecewise       |
    | linear supply cost curve, in $.                                         |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Variables                                                               |
    +=========================================================================+
    | | :code:`DRNew_Build_MWh`                                               |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Determines how much shiftable load capacity (in MWh) is built in each   |
    | operational period.                                                     |
    +-------------------------------------------------------------------------+
    | | :code:`DRNew_Cost`                                                    |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The cost of new shiftable load capacity in each operational period.     |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Expressions                                                             |
    +=========================================================================+
    | | :code:`DRNew_Energy_Capacity_MWh`                                     |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's total energy capacity (in MWh) in each operational period |
    | is the sum of the new-built energy capacity in all of the previous      |
    | periods.                                                                |
    +-------------------------------------------------------------------------+
    | | :code:`DRNew_Power_Capacity_MW`                                       |
    | | *Defined over*: :code:`DR_NEW_OPR_PRDS`                               |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | The project's total power capacity (in MW) in each operational period   |
    | is equal to the total energy capacity in that period, divided by the    |
    | project's minimum duraiton (in hours).                                  |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Constraints                                                             |
    +=========================================================================+
    | | :code:`DRNew_Cost_Constraint`                                         |
    | | *Defined over*: :code:`DR_NEW_PTS*PERIODS`                            |
    |                                                                         |
    | Ensures that the project's cost in each operational period is larger    |
    | than the calculated piecewise linear cost in each segment. Only one     |
    | segment will bind at a time.                                            |
    +-------------------------------------------------------------------------+

    """

    # Sets
    ###########################################################################

    m.DR_NEW = Set()

    m.DR_NEW_OPR_PRDS = Set(dimen=2, initialize=m.DR_NEW * m.PERIODS)

    m.DR_NEW_PTS = Set(dimen=2, within=m.DR_NEW * list(range(1, 1001)))

    # Required Params
    ###########################################################################

    m.dr_new_min_duration = Param(m.DR_NEW, within=NonNegativeReals)

    m.dr_new_min_cumulative_new_build_mwh = Param(
        m.DR_NEW, m.PERIODS, within=NonNegativeReals  # TODO: change to DR_NEW_OPR_PRDS?
    )

    m.dr_new_max_cumulative_new_build_mwh = Param(
        m.DR_NEW, m.PERIODS, within=NonNegativeReals  # TODO: change to DR_NEW_OPR_PRDS?
    )

    m.dr_new_supply_curve_slope = Param(m.DR_NEW_PTS, within=NonNegativeReals)

    m.dr_new_supply_curve_intercept = Param(m.DR_NEW_PTS, within=Reals)

    # Variables
    ###########################################################################

    m.DRNew_Build_MWh = Var(
        m.DR_NEW, m.PERIODS, within=NonNegativeReals  # TODO: change to DR_NEW_OPR_PRDS?
    )

    m.DRNew_Cost = Var(m.DR_NEW_OPR_PRDS, within=NonNegativeReals)

    # Expressions
    ###########################################################################

    m.DRNew_Energy_Capacity_MWh = Expression(
        m.DR_NEW_OPR_PRDS, rule=dr_new_energy_capacity_rule
    )

    m.DRNew_Power_Capacity_MW = Expression(
        m.DR_NEW_OPR_PRDS, rule=dr_new_power_capacity_rule
    )

    # Constraints
    ###########################################################################

    m.DRNew_Cost_Constraint = Constraint(
        m.DR_NEW_PTS * m.PERIODS, rule=cost_rule  # TODO: define new set?
    )

    # Dynamic Components
    ###########################################################################

    # Add to list of sets we'll join to get the final
    # PRJ_OPR_PRDS set
    getattr(d, capacity_type_operational_period_sets).append(
        "DR_NEW_OPR_PRDS",
    )
Beispiel #9
0
 def _pressure_bubble(self):
     self.pressure_bubble = Param(initialize=1e8,
                                  doc="Bubble point pressure (Pa)")
Beispiel #10
0
def Model_Creation_Dispatch(model):
    
    '''
    This function creates the instance for the resolution of the optimization in Pyomo.
    The problem is solved by discretizing the efficiency curve of the generators and uses binary variables
    
    :param model: Pyomo model as defined in the Micro-Grids library.
    
    '''
    from pyomo.environ import  Param, RangeSet, NonNegativeReals, Var, NonNegativeIntegers
    from Initialize import Initialize_Demand, Initialize_PV_Energy, Initialize_Demand_Dispatch, Initialize_PV_Energy_Dispatch, Marginal_Cost_Generator, Start_Cost,Marginal_Cost_Generator_1,Max_Power_Battery_Discharge, Max_Power_Battery_Charge # Import library with initialitation funtions for the parameters

    # Time parameters
    model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables 
    model.StartDate = Param() # Start date of the analisis
    model.PlotTime = Param() # Quantity of days that are going to be plot
    model.PlotDay = Param() # Start day for the plot
    
    #SETS
    model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year   
    # PARAMETERS
    
    # Parameters of the PV 

    model.Total_Energy_PV = Param(model.periods, within=NonNegativeReals, initialize=Initialize_PV_Energy_Dispatch) # Energy produccion of a solar panel in W
    
    # Parameters of the battery bank
    model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in  %
    model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in %
    model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in %
    model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours
    model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery  in hours                     
    model.Battery_Nominal_Capacity = Param(within=NonNegativeReals) # Capacity of the battery bank in Wh   
    model.Maximun_Charge_Power= Param(initialize=Max_Power_Battery_Charge) # Maximun charge power in w
    model.Maximun_Discharge_Power = Param(initialize=Max_Power_Battery_Discharge) #Maximun discharge power in w
    model.Battery_Initial_SOC = Param(within=NonNegativeReals) 
    # Parametes of the diesel generator
    model.Generator_Effiency = Param(within=NonNegativeReals)
    model.Generator_Min_Out_Put = Param(within=NonNegativeReals)
    model.Low_Heating_Value = Param() # Low heating value of the diesel in W/L
    model.Diesel_Cost = Param(within=NonNegativeReals) # Cost of diesel in USD/L
    model.Marginal_Cost_Generator_1 = Param(initialize=Marginal_Cost_Generator_1)
    model.Cost_Increase = Param(within=NonNegativeReals)
    model.Generator_Nominal_Capacity = Param(within=NonNegativeReals)
    model.Start_Cost_Generator = Param(within=NonNegativeReals, initialize=Start_Cost)  
    model.Marginal_Cost_Generator = Param(initialize=Marginal_Cost_Generator)
    
    # Parameters of the Energy balance                  
    model.Energy_Demand = Param(model.periods, initialize=Initialize_Demand_Dispatch) # Energy Energy_Demand in W 
    model.Lost_Load_Probability = Param() # Lost load probability in %
    model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W
    
    # Parameters of the proyect
    model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours
   
    # VARIABLES
            
    # Variables associated to the battery bank
    
    model.Energy_Battery_Flow_Out = Var(model.periods, within=NonNegativeReals) # Battery discharge energy in wh
    model.Energy_Battery_Flow_In = Var(model.periods, within=NonNegativeReals) # Battery charge energy in wh
    model.State_Of_Charge_Battery = Var(model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh
   
    
     # Variables associated to the diesel generator
    
    model.Period_Total_Cost_Generator = Var(model.periods, within=NonNegativeReals)    
    model.Energy_Generator_Total = Var(model.periods, within=NonNegativeReals)
    model.Integer_generator = Var(within=NonNegativeIntegers)
    model.Total_Cost_Generator = Var(within=NonNegativeReals)  
    model.Generator_Total_Period_Energy = Var(model.periods, within=NonNegativeReals)   
    model.Generator_Energy_Integer = Var(model.periods, within=NonNegativeIntegers)
    model.Last_Energy_Generator = Var(model.periods, within=NonNegativeReals)
    
    # Varialbles associated to the energy balance
    model.Lost_Load = Var(model.periods, within=NonNegativeReals) # Energy not suply by the system kWh
    model.Energy_Curtailment = Var(model.periods, within=NonNegativeReals) # Curtailment of solar energy in kWh
    
    # Variables associated to the project
    
    
    model.Scenario_Lost_Load_Cost = Var(within=NonNegativeReals) ####  
Beispiel #11
0
def Model_Creation(model):
    
    '''
    This function creates the instance for the resolution of the optimization in Pyomo.
    
    :param model: Pyomo model as defined in the Micro-Grids library.
    
    '''
    
    # Time parameters
    model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables
    model.Years = Param() # Number of years of the project
    model.StartDate = Param() # Start date of the analisis
    model.PlotTime = Param() # Quantity of days that are going to be plot
    model.PlotDay = Param() # Start day for the plot
    model.PlotScenario = Param()
    model.Scenarios = Param() 
    
    
    #SETS
    model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year
    model.years = RangeSet(1, model.Years) # Creation of a set from 1 to the number of years of the project
    model.scenario = RangeSet(1, model.Scenarios) # Creation of a set from 1 to the numbero scenarios to analized
    
    # PARAMETERS
    
    # Parameters of the PV 
    model.PV_Nominal_Capacity = Param(within=NonNegativeReals) # Nominal capacity of the PV in W/unit
    model.Inverter_Efficiency = Param() # Efficiency of the inverter in %
    model.PV_invesment_Cost = Param(within=NonNegativeReals) # Cost of solar panel in USD/W
    model.PV_Energy_Production = Param(model.scenario, model.periods, within=NonNegativeReals, initialize=Initialize_PV_Energy) # Energy produccion of a solar panel in W
    
    # Parameters of the battery bank
    model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in  %
    model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in %
    model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in %
    model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours
    model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery  in hours                     
    model.Battery_Reposition_Time = Param(within=NonNegativeReals) # Period of repocition of the battery in years
    model.Battery_Invesment_Cost = Param() # Cost of battery 
  
    # Parametes of the diesel generator
    model.Generator_Efficiency = Param() # Generator efficiency to trasform heat into electricity %
    model.Low_Heating_Value = Param() # Low heating value of the diesel in W/L
    model.Diesel_Unitary_Cost = Param(within=NonNegativeReals) # Cost of diesel in USD/L
    model.Generator_Invesment_Cost = Param(within=NonNegativeReals) # Cost of the diesel generator
    
        
    # Parameters of the Energy balance                  
    model.Energy_Demand = Param(model.scenario, model.periods, 
                                initialize=Initialize_Demand) # Energy Energy_Demand in W 
    model.Lost_Load_Probability = Param(within=NonNegativeReals) # Lost load probability in %
    model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W
    
    # Parameters of the proyect
    model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours
    model.Porcentage_Funded = Param(within=NonNegativeReals) # Porcentaje of the total investment that is Porcentage_Porcentage_Funded by a bank or another entity in %
    model.Project_Years = Param(model.years, initialize= Initialize_years) # Years of the project
    model.Maintenance_Operation_Cost_PV = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %                                             
    model.Maintenance_Operation_Cost_Battery = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %
    model.Maintenance_Operation_Cost_Generator = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %
    model.Discount_Rate = Param() # Discount rate of the project in %
    model.Interest_Rate_Loan = Param() # Interest rate of the loan in %
    model.Scenario_Weight = Param(model.scenario, within=NonNegativeReals) #########
       

    # VARIABLES
    
    # Variables associated to the solar panels
    model.PV_Units = Var(within=NonNegativeReals) # Number of units of solar panels
    model.Total_Energy_PV = Var(model.scenario,model.periods, within=NonNegativeReals) # Energy generated for the Pv sistem in Wh
    
    # Variables associated to the battery bank
    model.Battery_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity of the battery bank in Wh
    model.Energy_Battery_Flow_Out = Var(model.scenario, model.periods, within=NonNegativeReals) # Battery discharge energy in wh
    model.Energy_Battery_Flow_In = Var(model.scenario, model.periods, within=NonNegativeReals) # Battery charge energy in wh
    model.State_Of_Charge_Battery = Var(model.scenario, model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh
  
    
    # Variables associated to the diesel generator
    model.Generator_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity  of the diesel generator in Wh
    model.Diesel_Consume = Var(model.scenario,model.periods, within=NonNegativeReals) # Diesel consumed to produce electric energy in L
    model.Generator_Energy = Var(model.scenario, model.periods, within=NonNegativeReals) # Energy generated for the Diesel generator
    model.Diesel_Cost_Total = Var(model.scenario, within=NonNegativeReals)
    
    
    
    # Varialbles associated to the energy balance
    model.Lost_Load = Var(model.scenario, model.periods, within=NonNegativeReals) # Energy not suply by the system kWh
    model.Energy_Curtailment = Var(model.scenario, model.periods, within=NonNegativeReals) # Curtailment of solar energy in kWh
    model.Scenario_Lost_Load_Cost = Var(model.scenario, within=NonNegativeReals) ####    

    # Variables associated to the project
    model.Cost_Financial = Var(within=NonNegativeReals) # Financial cost of each period in USD
    model.Scenario_Net_Present_Cost = Var(model.scenario, within=NonNegativeReals) ####
    model.Initial_Inversion = Var(within=NonNegativeReals)
    model.Operation_Maintenance_Cost = Var(within=NonNegativeReals)
    model.Total_Finalcial_Cost = Var(within=NonNegativeReals)
    model.Battery_Reposition_Cost = Var(within=NonNegativeReals)
Beispiel #12
0
def Model_Creation_Integer(model):
    
    '''
    This function creates the instance for the resolution of the optimization in Pyomo.
    The problem is solved by discretizing the efficiency curve of the generators and uses binary variables
    
    :param model: Pyomo model as defined in the Micro-Grids library.
    
    '''
    from pyomo.environ import  Param, RangeSet, NonNegativeReals, Var, NonNegativeIntegers
    from Initialize import Initialize_years, Initialize_Demand, Marginal_Cost_Generator, Start_Cost, Marginal_Cost_Generator_1, Capital_Recovery_Factor,Battery_Reposition_Cost, Initialize_Renewable_Energy # Import library with initialitation funtions for the parameters
   
    # Time parameters
    model.Periods = Param(within=NonNegativeReals) # Number of periods of analysis of the energy variables
    model.Years = Param() # Number of years of the project
    model.StartDate = Param() # Start date of the analisis
    model.PlotTime = Param() # Quantity of days that are going to be plot
    model.PlotDay = Param() # Start day for the plot
    model.Scenarios = Param()  
    model.PlotScenario = Param()
    model.Renewable_Source = Param()
    model.Generator_Type = Param()
    
    #SETS
    model.periods = RangeSet(1, model.Periods) # Creation of a set from 1 to the number of periods in each year
    model.years = RangeSet(1, model.Years) # Creation of a set from 1 to the number of years of the project
    model.scenario = RangeSet(1, model.Scenarios) # Creation of a set from 1 to the numbero scenarios to analized
    model.renewable_source = RangeSet(1, model.Renewable_Source)
    model.generator_type = RangeSet(1, model.Generator_Type)
    
    # PARAMETERS
    
    # Parameters of the PV 
    model.Renewable_Nominal_Capacity = Param(model.renewable_source, 
                                             within=NonNegativeReals)
    model.Inverter_Efficiency_Renewable = Param(model.renewable_source, 
                                                within=NonNegativeReals)
    model.Renewable_Invesment_Cost = Param(model.renewable_source, 
                                           within=NonNegativeReals)
    model.Renewable_Energy_Production = Param(model.scenario, 
                                              model.renewable_source, 
                                              model.periods,
                                              initialize=Initialize_Renewable_Energy)
    
    
 #instance.Renewable_Invesment_Cost.extract_values()   
    # Parameters of the battery bank
    model.Charge_Battery_Efficiency = Param() # Efficiency of the charge of the battery in  %
    model.Discharge_Battery_Efficiency = Param() # Efficiency of the discharge of the battery in %
    model.Deep_of_Discharge = Param() # Deep of discharge of the battery (Deep_of_Discharge) in %
    model.Maximun_Battery_Charge_Time = Param(within=NonNegativeReals) # Minimun time of charge of the battery in hours
    model.Maximun_Battery_Discharge_Time = Param(within=NonNegativeReals) # Maximun time of discharge of the battery  in hours                     
    model.Battery_Invesment_Cost = Param(within=NonNegativeReals) # Cost of battery 
    model.Battery_Cycles = Param(within=NonNegativeReals)
    model.Battery_Reposition_Cost = Param(within=NonNegativeReals, 
                                          initialize=Battery_Reposition_Cost)
    
    
    
    # Parametes of the diesel generator
    model.Generator_Min_Out_Put = Param(model.generator_type,
                                        within=NonNegativeReals)
    model.Generator_Efficiency = Param(model.generator_type) # Generator efficiency to trasform heat into electricity %
    model.Low_Heating_Value = Param(model.generator_type) # Low heating value of the diesel in W/L
    model.Fuel_Cost = Param(model.generator_type,
                              within=NonNegativeReals) # Cost of diesel in USD/L
    model.Generator_Invesment_Cost = Param(model.generator_type,within=NonNegativeReals) # Cost of the diesel generator  
    model.Marginal_Cost_Generator_1 = Param(model.generator_type,
                                            initialize=Marginal_Cost_Generator_1)
    model.Cost_Increase = Param(model.generator_type,
                                within=NonNegativeReals)
    model.Generator_Nominal_Capacity = Param(model.generator_type,
                                             within=NonNegativeReals)
    model.Start_Cost_Generator = Param(model.generator_type,
                                       within=NonNegativeReals, initialize=Start_Cost)  
    model.Marginal_Cost_Generator = Param(model.generator_type,
                                          initialize=Marginal_Cost_Generator)
    
    # Parameters of the Energy balance                  
    model.Energy_Demand = Param(model.scenario,model.periods, initialize=Initialize_Demand) # Energy Energy_Demand in W 
    model.Lost_Load_Probability = Param() # Lost load probability in %
    model.Value_Of_Lost_Load = Param(within=NonNegativeReals) # Value of lost load in USD/W
    
    # Parameters of the proyect
    model.Delta_Time = Param(within=NonNegativeReals) # Time step in hours
    model.Project_Years = Param(model.years, initialize= Initialize_years) # Years of the project
    model.Maintenance_Operation_Cost_Renewable = Param(model.renewable_source, within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %                                             
    model.Maintenance_Operation_Cost_Battery = Param(within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %
    model.Maintenance_Operation_Cost_Generator = Param(model.generator_type,
                                                       within=NonNegativeReals) # Percentage of the total investment spend in operation and management of solar panels in each period in %
    model.Discount_Rate = Param() # Discount rate of the project in %
    model.Scenario_Weight = Param(model.scenario, within=NonNegativeReals)
    model.Capital_Recovery_Factor = Param(within=NonNegativeReals, initialize= Capital_Recovery_Factor) 
    # VARIABLES
    
    # Variables associated to the solar panels
      
    model.Renewable_Units = Var(model.renewable_source, within=NonNegativeReals)
    
    # Variables associated to the battery bank
    model.Battery_Nominal_Capacity = Var(within=NonNegativeReals) # Capacity of the battery bank in Wh
    model.Energy_Battery_Flow_Out = Var(model.scenario,model.periods, within=NonNegativeReals) # Battery discharge energy in wh
    model.Energy_Battery_Flow_In = Var(model.scenario,model.periods, within=NonNegativeReals) # Battery charge energy in wh
    model.State_Of_Charge_Battery = Var(model.scenario,model.periods, within=NonNegativeReals) # State of Charge of the Battery in wh
        
     # Variables associated to the diesel generator
    
    model.Energy_Generator_Total = Var(model.scenario,model.generator_type,
                                       model.periods, within=NonNegativeReals)
    model.Integer_generator = Var(model.generator_type,
                                  within=NonNegativeIntegers)
    
    model.Generator_Total_Period_Energy = Var(model.scenario,
                                              model.generator_type,
                                              model.periods, 
                                              within=NonNegativeReals)   
    model.Generator_Energy_Integer = Var(model.scenario, model.generator_type,
                                         model.periods, within=NonNegativeIntegers)
    model.Last_Energy_Generator = Var(model.scenario, model.generator_type,
                                      model.periods, within=NonNegativeReals)
    
    # Varialbles associated to the energy balance
    model.Lost_Load = Var(model.scenario,model.periods, within=NonNegativeReals) # Energy not suply by the system kWh
    model.Energy_Curtailment = Var(model.scenario,model.periods, 
                                   within=NonNegativeReals) # Curtailment of solar energy in kWh
Beispiel #13
0
import pyomo.environ
from pyomo.environ import ConcreteModel, AbstractModel, Param, RangeSet, Set, BuildAction, Var, Objective, Piecewise, minimize, value
from pyomo.environ import NonNegativeReals, Integers, Binary, PositiveIntegers
from pyomo.opt import SolverStatus, TerminationCondition
from pyomo.opt import SolverFactory
from support import *
#%% take care of input data
machine = pd.read_excel(r"system load.xlsx")
cost_para = pd.read_excel(r"cost parameter.xlsx")
cost_para["Product_cost_ini"] = cost_para['a'] + cost_para['b'] * machine[
    "Pmin"] + cost_para['c'] * machine["Pmin"]**2
load = pd.read_excel(r"load.xlsx")
#%% create absmodel
amodel = AbstractModel()
amodel.generator = Set(initialize=machine["Units"])
amodel.nperiods = Param(within=PositiveIntegers, initialize=len(load))
amodel.periods = RangeSet(1, amodel.nperiods)
amodel.demand = Param(amodel.periods,
                      within=NonNegativeReals,
                      initialize=modifyind(load['demand']))
amodel.reserve = Param(amodel.periods,
                       within=NonNegativeReals,
                       default=0.0,
                       initialize=modifyind(load['demand'] * 0.1))
amodel.minout = Param(amodel.generator,
                      within=NonNegativeReals,
                      default=0.0,
                      initialize=modifyind(machine["Pmin"]))
amodel.maxout = Param(amodel.generator,
                      within=NonNegativeReals,
                      validate=check_max_power,
Beispiel #14
0
def test_not_var(model):
    model.p = Param()

    with pytest.raises(TypeError):
        homotopy(model, [model.p], [20])
Beispiel #15
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(BTParameterData, self).build()

        self.cubic_type = CubicEoS.PR

        # Add Component objects
        self.benzene = Component(
            default={"elemental_composition": {
                "C": 6,
                "H": 6
            }})
        self.toluene = Component(
            default={"elemental_composition": {
                "C": 7,
                "H": 8
            }})

        # List of phase equilibrium index
        self.phase_equilibrium_idx = Set(initialize=[1, 2])

        self.phase_equilibrium_list = \
            {1: ["benzene", ("Vap", "Liq")],
             2: ["toluene", ("Vap", "Liq")]}

        # Thermodynamic reference state
        self.pressure_ref = Param(mutable=True,
                                  default=101325,
                                  doc='Reference pressure [Pa]',
                                  units=pyunits.Pa)
        self.temperature_ref = Param(mutable=True,
                                     default=298.15,
                                     doc='Reference temperature [K]',
                                     units=pyunits.K)

        # Critical Properties
        pressure_crit_data = {'benzene': 48.9e5, 'toluene': 41.0e5}

        self.pressure_crit = Param(self.component_list,
                                   within=NonNegativeReals,
                                   mutable=False,
                                   initialize=extract_data(pressure_crit_data),
                                   doc='Critical pressure [Pa]',
                                   units=pyunits.Pa)

        temperature_crit_data = {'benzene': 562.2, 'toluene': 591.8}

        self.temperature_crit = Param(
            self.component_list,
            within=NonNegativeReals,
            mutable=False,
            initialize=extract_data(temperature_crit_data),
            doc='Critical temperature [K]',
            units=pyunits.K)

        # Pitzer acentricity factor
        omega_data = {'benzene': 0.212, 'toluene': 0.263}

        self.omega = Param(self.component_list,
                           within=Reals,
                           mutable=False,
                           initialize=extract_data(omega_data),
                           doc='Acentricity Factor')

        # Peng-Robinson binary interaction parameters
        kappa_data = {
            ('benzene', 'benzene'): 0.0000,
            ('benzene', 'toluene'): 0.0000,
            ('toluene', 'benzene'): 0.0000,
            ('toluene', 'toluene'): 0.0000
        }

        self.kappa = Param(self.component_list,
                           self.component_list,
                           within=Reals,
                           mutable=False,
                           initialize=extract_data(kappa_data),
                           doc='Peng-Robinson binary interaction parameters')

        # Molecular Weights
        mw_comp_data = {'benzene': 78.1136E-3, 'toluene': 92.1405E-3}

        self.mw_comp = Param(self.component_list,
                             mutable=False,
                             initialize=extract_data(mw_comp_data),
                             doc="molecular weight kg/mol",
                             units=pyunits.kg / pyunits.mol)

        # Constants for specific heat capacity, enthalpy and entropy
        self.cp_mol_ig_comp_coeff_1 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -3.392E1,
                'toluene': -2.435E1
            },
            doc="Parameter 1 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K)

        self.cp_mol_ig_comp_coeff_2 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 4.739E-1,
                'toluene': 5.125E-1
            },
            doc="Parameter 2 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**2)

        self.cp_mol_ig_comp_coeff_3 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -3.017E-4,
                'toluene': -2.765E-4
            },
            doc="Parameter 3 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**3)

        self.cp_mol_ig_comp_coeff_4 = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 7.130E-8,
                'toluene': 4.911E-8
            },
            doc="Parameter 4 to compute cp_mol_comp",
            units=pyunits.J / pyunits.mol / pyunits.K**4)

        # Standard heats of formation
        # Source: NIST Webbook, https://webbook.nist.gov
        # Retrieved 25th September 2019
        dh_form_data = {'benzene': 82.9e3, 'toluene': 50.1e3}

        self.enth_mol_form_ref = Param(self.component_list,
                                       mutable=False,
                                       initialize=extract_data(dh_form_data),
                                       doc="Standard heats of formation",
                                       units=pyunits.J / pyunits.mol)

        # Standard entropy of formation
        # Source: Engineering Toolbox, https://www.engineeringtoolbox.com
        # Retrieved 25th September, 2019
        ds_form_data = {'benzene': -269, 'toluene': -321}

        self.entr_mol_form_ref = Param(self.component_list,
                                       mutable=False,
                                       initialize=extract_data(ds_form_data),
                                       doc="Standard entropy of formation",
                                       units=pyunits.J / pyunits.mol /
                                       pyunits.K)

        # Antoine coefficients for ideal vapour (units: bar, K)
        # This is needed for initial guesses of bubble and dew points
        self.antoine_coeff_A = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 4.202,
                'toluene': 4.216
            },
            doc="Antoine A Parameter to calculate pressure_sat",
            units=pyunits.dimensionless)

        self.antoine_coeff_B = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': 1322,
                'toluene': 1435
            },
            doc="Antoine B Parameter to calculate pressure_sat",
            units=pyunits.K)

        self.antoine_coeff_C = Param(
            self.component_list,
            mutable=False,
            initialize={
                'benzene': -38.56,
                'toluene': -43.33
            },
            doc="Antoine C Parameter to calculate pressure_sat",
            units=pyunits.K)
Beispiel #16
0
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(HDAParameterData, self).build()

        self.state_block_class = IdealStateBlock

        self.component_list = Set(
            initialize=['benzene', 'toluene', 'hydrogen', 'methane'])

        self.phase_list = Set(initialize=['Liq', 'Vap'], ordered=True)

        # List of components in each phase (optional)
        self.phase_comp = {
            "Liq": self.component_list,
            "Vap": self.component_list
        }

        # List of phase equilibrium index
        self.phase_equilibrium_idx = Set(initialize=[1, 2, 3, 4, 5])

        self.phase_equilibrium_list = \
            {1: ["benzene", ("Vap", "Liq")],
             2: ["toluene", ("Vap", "Liq")],
             3: ["hydrogen", ("Vap", "Liq")],
             4: ["methane", ("Vap", "Liq")],
             5: ["diphenyl", ("Vap", "Liq")]}

        # Thermodynamic reference state
        self.pressure_ref = Param(mutable=True,
                                  default=101325,
                                  doc='Reference pressure [Pa]')
        self.temperature_ref = Param(mutable=True,
                                     default=298.15,
                                     doc='Reference temperature [K]')

        # Source: The Properties of Gases and Liquids (1987)
        # 4th edition, Chemical Engineering Series - Robert C. Reid
        pressure_crit_data = {
            'benzene': 48.9e5,
            'toluene': 41e5,
            'hydrogen': 12.9e5,
            'methane': 46e5,
            'diphenyl': 38.5e5
        }

        self.pressure_crit = Param(self.component_list,
                                   within=NonNegativeReals,
                                   mutable=False,
                                   initialize=extract_data(pressure_crit_data),
                                   doc='Critical pressure [Pa]')

        # Source: The Properties of Gases and Liquids (1987)
        # 4th edition, Chemical Engineering Series - Robert C. Reid
        temperature_crit_data = {
            'benzene': 562.2,
            'toluene': 591.8,
            'hydrogen': 33.0,
            'methane': 190.4,
            'diphenyl': 789
        }

        self.temperature_crit = Param(
            self.component_list,
            within=NonNegativeReals,
            mutable=False,
            initialize=extract_data(temperature_crit_data),
            doc='Critical temperature [K]')

        # Gas Constant
        self.gas_const = Param(within=NonNegativeReals,
                               mutable=False,
                               default=8.314,
                               doc='Gas Constant [J/mol.K]')

        # Source: The Properties of Gases and Liquids (1987)
        # 4th edition, Chemical Engineering Series - Robert C. Reid
        mw_comp_data = {
            'benzene': 78.1136E-3,
            'toluene': 92.1405E-3,
            'hydrogen': 2.016e-3,
            'methane': 16.043e-3,
            'diphenyl': 154.212e-4
        }

        self.mw_comp = Param(self.component_list,
                             mutable=False,
                             initialize=extract_data(mw_comp_data),
                             doc="molecular weight Kg/mol")

        # Constants for liquid densities
        # Source: Perry's Chemical Engineers Handbook
        #         - Robert H. Perry (Cp_liq)
        dens_liq_data = {
            ('benzene', '1'): 1.0162,
            ('benzene', '2'): 0.2655,
            ('benzene', '3'): 562.16,
            ('benzene', '4'): 0.28212,
            ('toluene', '1'): 0.8488,
            ('toluene', '2'): 0.26655,
            ('toluene', '3'): 591.8,
            ('toluene', '4'): 0.2878,
            ('hydrogen', '1'): 5.414,
            ('hydrogen', '2'): 0.34893,
            ('hydrogen', '3'): 33.19,
            ('hydrogen', '4'): 0.2706,
            ('methane', '1'): 2.9214,
            ('methane', '2'): 0.28976,
            ('methane', '3'): 190.56,
            ('methane', '4'): 0.28881,
            ('diphenyl', '1'): 0.5039,
            ('diphenyl', '2'): 0.25273,
            ('diphenyl', '3'): 789.26,
            ('diphenyl', '4'): 0.281
        }

        self.dens_liq_params = Param(
            self.component_list, ['1', '2', '3', '4'],
            mutable=False,
            initialize=extract_data(dens_liq_data),
            doc="Parameters to compute liquid densities")

        # Boiling point at standard pressure
        # Source: Perry's Chemical Engineers Handbook
        #         - Robert H. Perry (Cp_liq)
        bp_data = {
            ('benzene'): 353.25,
            ('toluene'): 383.95,
            ('hydrogen'): 20.45,
            ('methane'): 111.75,
            ('diphenyl'): 528.05
        }

        self.temperature_boil = Param(
            self.component_list,
            mutable=False,
            initialize=extract_data(bp_data),
            doc="Pure component boiling points at standard pressure [K]")

        # Constants for specific heat capacity, enthalpy
        # Sources: The Properties of Gases and Liquids (1987)
        #         4th edition, Chemical Engineering Series - Robert C. Reid
        #         Perry's Chemical Engineers Handbook
        #         - Robert H. Perry (Cp_liq)
        cp_ig_data = {
            ('Liq', 'benzene', '1'): 1.29E5,
            ('Liq', 'benzene', '2'): -1.7E2,
            ('Liq', 'benzene', '3'): 6.48E-1,
            ('Liq', 'benzene', '4'): 0,
            ('Liq', 'benzene', '5'): 0,
            ('Vap', 'benzene', '1'): -3.392E1,
            ('Vap', 'benzene', '2'): 4.739E-1,
            ('Vap', 'benzene', '3'): -3.017E-4,
            ('Vap', 'benzene', '4'): 7.130E-8,
            ('Vap', 'benzene', '5'): 0,
            ('Liq', 'toluene', '1'): 1.40E5,
            ('Liq', 'toluene', '2'): -1.52E2,
            ('Liq', 'toluene', '3'): 6.95E-1,
            ('Liq', 'toluene', '4'): 0,
            ('Liq', 'toluene', '5'): 0,
            ('Vap', 'toluene', '1'): -2.435E1,
            ('Vap', 'toluene', '2'): 5.125E-1,
            ('Vap', 'toluene', '3'): -2.765E-4,
            ('Vap', 'toluene', '4'): 4.911E-8,
            ('Vap', 'toluene', '5'): 0,
            ('Liq', 'hydrogen', '1'): 0,  # 6.6653e1,
            ('Liq', 'hydrogen', '2'): 0,  # 6.7659e3,
            ('Liq', 'hydrogen', '3'): 0,  # -1.2363e2,
            ('Liq', 'hydrogen', '4'): 0,  # 4.7827e2, # Eqn 2
            ('Liq', 'hydrogen', '5'): 0,
            ('Vap', 'hydrogen', '1'): 2.714e1,
            ('Vap', 'hydrogen', '2'): 9.274e-3,
            ('Vap', 'hydrogen', '3'): -1.381e-5,
            ('Vap', 'hydrogen', '4'): 7.645e-9,
            ('Vap', 'hydrogen', '5'): 0,
            ('Liq', 'methane', '1'): 0,  # 6.5708e1,
            ('Liq', 'methane', '2'): 0,  # 3.8883e4,
            ('Liq', 'methane', '3'): 0,  # -2.5795e2,
            ('Liq', 'methane', '4'): 0,  # 6.1407e2, # Eqn 2
            ('Liq', 'methane', '5'): 0,
            ('Vap', 'methane', '1'): 1.925e1,
            ('Vap', 'methane', '2'): 5.213e-2,
            ('Vap', 'methane', '3'): 1.197e-5,
            ('Vap', 'methane', '4'): -1.132e-8,
            ('Vap', 'methane', '5'): 0,
            ('Liq', 'diphenyl', '1'): 1.2177e5,
            ('Liq', 'diphenyl', '2'): 4.2930e2,
            ('Liq', 'diphenyl', '3'): 0,
            ('Liq', 'diphenyl', '4'): 0,
            ('Liq', 'diphenyl', '5'): 0,
            ('Vap', 'diphenyl', '1'): -9.707e1,
            ('Vap', 'diphenyl', '2'): 1.106e0,
            ('Vap', 'diphenyl', '3'): -8.855e-4,
            ('Vap', 'diphenyl', '4'): 2.790e-7,
            ('Vap', 'diphenyl', '5'): 0
        }

        self.cp_ig = Param(self.phase_list,
                           self.component_list, ['1', '2', '3', '4', '5'],
                           mutable=False,
                           initialize=extract_data(cp_ig_data),
                           doc="parameters to compute Cp_comp")

        # Source: The Properties of Gases and Liquids (1987)
        # 4th edition, Chemical Engineering Series - Robert C. Reid
        # fitted to Antoine form
        # H2, Methane from NIST webbook
        pressure_sat_coeff_data = {
            ('benzene', 'A'): 4.202,
            ('benzene', 'B'): 1322,
            ('benzene', 'C'): -38.56,
            ('toluene', 'A'): 4.216,
            ('toluene', 'B'): 1435,
            ('toluene', 'C'): -43.33,
            ('hydrogen', 'A'): 3.543,
            ('hydrogen', 'B'): 99.40,
            ('hydrogen', 'C'): 7.726,
            ('methane', 'A'): 3.990,
            ('methane', 'B'): 443.0,
            ('methane', 'C'): -0.49,
            ('diphenyl', 'A'): 4.345,
            ('diphenyl', 'B'): 1988,
            ('diphenyl', 'C'): -70.82
        }

        self.pressure_sat_coeff = Param(
            self.component_list, ['A', 'B', 'C'],
            mutable=False,
            initialize=extract_data(pressure_sat_coeff_data),
            doc="parameters to compute Cp_comp")

        # Source: The Properties of Gases and Liquids (1987)
        # 4th edition, Chemical Engineering Series - Robert C. Reid
        dh_vap = {
            'benzene': 3.387e4,
            'toluene': 3.8262e4,
            'hydrogen': 0,
            'methane': 0,
            "diphenyl": 6.271e4
        }

        self.dh_vap = Param(self.component_list,
                            mutable=False,
                            initialize=extract_data(dh_vap),
                            doc="heat of vaporization")
Beispiel #17
0
    def build(self):
        """
        Callable method for Block construction.
        """
        super(WaterParameterData, self).build()

        self._state_block_class = WaterStateBlock

        # components
        self.H2O = Component()

        # phases
        self.Liq = LiquidPhase()
        self.Vap = VaporPhase()
        """ References
        This package was developed from the following references:

        - K.G.Nayar, M.H.Sharqawy, L.D.Banchik, and J.H.Lienhard V, "Thermophysical properties of seawater: A review and
        new correlations that include pressure dependence,"Desalination, Vol.390, pp.1 - 24, 2016.
        doi: 10.1016/j.desal.2016.02.024(preprint)

        - Mostafa H.Sharqawy, John H.Lienhard V, and Syed M.Zubair, "Thermophysical properties of seawater: A review of 
        existing correlations and data,"Desalination and Water Treatment, Vol.16, pp.354 - 380, April 2010.
        (2017 corrections provided at http://web.mit.edu/seawater)
        """

        # Parameters
        # molecular weight
        self.mw_comp = Param(
            self.component_list,
            mutable=False,
            initialize=18.01528e-3,
            units=pyunits.kg / pyunits.mol,
            doc="Molecular weight",
        )

        # Liq mass density parameters, eq. 8 in Sharqawy et al. (2010)
        dens_units = pyunits.kg / pyunits.m**3
        t_inv_units = pyunits.K**-1
        s_inv_units = pyunits.kg / pyunits.g

        self.dens_mass_param_A1 = Var(
            within=Reals,
            initialize=9.999e2,
            units=dens_units,
            doc="Mass density parameter A1",
        )
        self.dens_mass_param_A2 = Var(
            within=Reals,
            initialize=2.034e-2,
            units=dens_units * t_inv_units,
            doc="Mass density parameter A2",
        )
        self.dens_mass_param_A3 = Var(
            within=Reals,
            initialize=-6.162e-3,
            units=dens_units * t_inv_units**2,
            doc="Mass density parameter A3",
        )
        self.dens_mass_param_A4 = Var(
            within=Reals,
            initialize=2.261e-5,
            units=dens_units * t_inv_units**3,
            doc="Mass density parameter A4",
        )
        self.dens_mass_param_A5 = Var(
            within=Reals,
            initialize=-4.657e-8,
            units=dens_units * t_inv_units**4,
            doc="Mass density parameter A5",
        )

        # Vap mass density parameters (approximating using ideal gas)
        self.dens_mass_param_mw = Var(
            within=Reals,
            initialize=18.01528e-3,
            units=pyunits.kg / pyunits.mol,
            doc="Mass density parameter molecular weight",
        )
        self.dens_mass_param_R = Var(
            within=Reals,
            initialize=8.31462618,
            units=pyunits.J / pyunits.mol / pyunits.K,
            doc="Mass density parameter universal gas constant",
        )

        # vapor pressure parameters,  eq. 5 and 6 in Nayar et al.(2016)
        self.pressure_sat_param_psatw_A1 = Var(
            within=Reals,
            initialize=-5.8002206e3,
            units=pyunits.K,
            doc="Vapor pressure of pure water parameter A1",
        )
        self.pressure_sat_param_psatw_A2 = Var(
            within=Reals,
            initialize=1.3914993,
            units=pyunits.dimensionless,
            doc="Vapor pressure of pure water parameter A2",
        )
        self.pressure_sat_param_psatw_A3 = Var(
            within=Reals,
            initialize=-4.8640239e-2,
            units=t_inv_units,
            doc="Vapor pressure of pure water parameter A3",
        )
        self.pressure_sat_param_psatw_A4 = Var(
            within=Reals,
            initialize=4.1764768e-5,
            units=t_inv_units**2,
            doc="Vapor pressure of pure water parameter A4",
        )
        self.pressure_sat_param_psatw_A5 = Var(
            within=Reals,
            initialize=-1.4452093e-8,
            units=t_inv_units**3,
            doc="Vapor pressure of pure water parameter A5",
        )
        self.pressure_sat_param_psatw_A6 = Var(
            within=Reals,
            initialize=6.5459673,
            units=pyunits.dimensionless,
            doc="Vapor pressure of pure water parameter A6",
        )

        # specific enthalpy parameters, eq. 55 and 43 in Sharqawy et al. (2010)
        enth_mass_units = pyunits.J / pyunits.kg

        self.enth_mass_param_A1 = Var(
            within=Reals,
            initialize=141.355,
            units=enth_mass_units,
            doc="Specific enthalpy parameter A1",
        )
        self.enth_mass_param_A2 = Var(
            within=Reals,
            initialize=4202.07,
            units=enth_mass_units * t_inv_units,
            doc="Specific enthalpy parameter A2",
        )
        self.enth_mass_param_A3 = Var(
            within=Reals,
            initialize=-0.535,
            units=enth_mass_units * t_inv_units**2,
            doc="Specific enthalpy parameter A3",
        )
        self.enth_mass_param_A4 = Var(
            within=Reals,
            initialize=0.004,
            units=enth_mass_units * t_inv_units**3,
            doc="Specific enthalpy parameter A4",
        )
        # self.enth_mass_param_B1 = Var(
        #     within=Reals, initialize=-2.348e4, units=enth_mass_units,
        #     doc='Specific enthalpy parameter B1')
        # self.enth_mass_param_B2 = Var(
        #     within=Reals, initialize=3.152e5, units=enth_mass_units,
        #     doc='Specific enthalpy parameter B2')
        # self.enth_mass_param_B3 = Var(
        #     within=Reals, initialize=2.803e6, units=enth_mass_units,
        #     doc='Specific enthalpy parameter B3')
        # self.enth_mass_param_B4 = Var(
        #     within=Reals, initialize=-1.446e7, units=enth_mass_units,
        #     doc='Specific enthalpy parameter B4')
        # self.enth_mass_param_B5 = Var(
        #     within=Reals, initialize=7.826e3, units=enth_mass_units * t_inv_units,
        #     doc='Specific enthalpy parameter B5')
        # self.enth_mass_param_B6 = Var(
        #     within=Reals, initialize=-4.417e1, units=enth_mass_units * t_inv_units**2,
        #     doc='Specific enthalpy parameter B6')
        # self.enth_mass_param_B7 = Var(
        #     within=Reals, initialize=2.139e-1, units=enth_mass_units * t_inv_units**3,
        #     doc='Specific enthalpy parameter B7')
        # self.enth_mass_param_B8 = Var(
        #     within=Reals, initialize=-1.991e4, units=enth_mass_units * t_inv_units,
        #     doc='Specific enthalpy parameter B8')
        # self.enth_mass_param_B9 = Var(
        #     within=Reals, initialize=2.778e4, units=enth_mass_units * t_inv_units,
        #     doc='Specific enthalpy parameter B9')
        # self.enth_mass_param_B10 = Var(
        #     within=Reals, initialize=9.728e1, units=enth_mass_units * t_inv_units**2,
        #     doc='Specific enthalpy parameter B10')

        # specific heat parameters from eq (9) in Sharqawy et al. (2010)
        cp_units = pyunits.J / (pyunits.kg * pyunits.K)
        self.cp_phase_param_A1 = Var(
            within=Reals,
            initialize=5.328,
            units=cp_units,
            doc="Specific heat of seawater parameter A1",
        )
        # self.cp_phase_param_A2 = Var(
        #     within=Reals, initialize=-9.76e-2, units=cp_units * s_inv_units,
        #     doc='Specific heat of seawater parameter A2')
        # self.cp_phase_param_A3 = Var(
        #     within=Reals, initialize=4.04e-4, units=cp_units * s_inv_units**2,
        #     doc='Specific heat of seawater parameter A3')
        self.cp_phase_param_B1 = Var(
            within=Reals,
            initialize=-6.913e-3,
            units=cp_units * t_inv_units,
            doc="Specific heat of seawater parameter B1",
        )
        # self.cp_phase_param_B2 = Var(
        #     within=Reals, initialize=7.351e-4, units=cp_units * s_inv_units * t_inv_units,
        #     doc='Specific heat of seawater parameter B2')
        # self.cp_phase_param_B3 = Var(
        #     within=Reals, initialize=-3.15e-6, units=cp_units * s_inv_units**2 * t_inv_units,
        #     doc='Specific heat of seawater parameter B3')
        self.cp_phase_param_C1 = Var(
            within=Reals,
            initialize=9.6e-6,
            units=cp_units * t_inv_units**2,
            doc="Specific heat of seawater parameter C1",
        )
        # self.cp_phase_param_C2 = Var(
        #     within=Reals, initialize=-1.927e-6, units=cp_units * s_inv_units * t_inv_units**2,
        #     doc='Specific heat of seawater parameter C2')
        # self.cp_phase_param_C3 = Var(
        #     within=Reals, initialize=8.23e-9, units=cp_units * s_inv_units**2 * t_inv_units**2,
        #     doc='Specific heat of seawater parameter C3')
        self.cp_phase_param_D1 = Var(
            within=Reals,
            initialize=2.5e-9,
            units=cp_units * t_inv_units**3,
            doc="Specific heat of seawater parameter D1",
        )
        # self.cp_phase_param_D2 = Var(
        #     within=Reals, initialize=1.666e-9, units=cp_units * s_inv_units * t_inv_units**3,
        #     doc='Specific heat of seawater parameter D2')
        # self.cp_phase_param_D3 = Var(
        #     within=Reals, initialize=-7.125e-12, units=cp_units * s_inv_units**2 * t_inv_units**3,
        #     doc='Specific heat of seawater parameter D3')

        # Specific heat parameters for Cp vapor from NIST Webbook
        # Chase, M.W., Jr., NIST-JANAF Themochemical Tables, Fourth Edition, J. Phys. Chem. Ref. Data, Monograph 9, 1998, 1-1951
        self.cp_vap_param_A = Var(
            within=Reals,
            initialize=30.09200 / 18.01528e-3,
            units=cp_units,
            doc="Specific heat of water vapor parameter A",
        )
        self.cp_vap_param_B = Var(
            within=Reals,
            initialize=6.832514 / 18.01528e-3,
            units=cp_units * t_inv_units,
            doc="Specific heat of water vapor parameter B",
        )
        self.cp_vap_param_C = Var(
            within=Reals,
            initialize=6.793435 / 18.01528e-3,
            units=cp_units * t_inv_units**2,
            doc="Specific heat of water vapor parameter C",
        )
        self.cp_vap_param_D = Var(
            within=Reals,
            initialize=-2.534480 / 18.01528e-3,
            units=cp_units * t_inv_units**3,
            doc="Specific heat of water vapor parameter D",
        )
        self.cp_vap_param_E = Var(
            within=Reals,
            initialize=0.082139 / 18.01528e-3,
            units=cp_units * t_inv_units**-2,
            doc="Specific heat of water vapor parameter E",
        )

        # latent heat of pure water parameters from eq. 54 in Sharqawy et al. (2010)
        self.dh_vap_w_param_0 = Var(
            within=Reals,
            initialize=2.501e6,
            units=enth_mass_units,
            doc="Latent heat of pure water parameter 0",
        )
        self.dh_vap_w_param_1 = Var(
            within=Reals,
            initialize=-2.369e3,
            units=cp_units,
            doc="Latent heat of pure water parameter 1",
        )
        self.dh_vap_w_param_2 = Var(
            within=Reals,
            initialize=2.678e-1,
            units=enth_mass_units * t_inv_units**2,
            doc="Latent heat of pure water parameter 2",
        )
        self.dh_vap_w_param_3 = Var(
            within=Reals,
            initialize=-8.103e-3,
            units=enth_mass_units * t_inv_units**3,
            doc="Latent heat of pure water parameter 3",
        )
        self.dh_vap_w_param_4 = Var(
            within=Reals,
            initialize=-2.079e-5,
            units=enth_mass_units * t_inv_units**4,
            doc="Latent heat of pure water parameter 4",
        )

        # traditional parameters are the only Vars currently on the block and should be fixed
        for v in self.component_objects(Var):
            v.fix()

        # ---default scaling---
        self.set_default_scaling("temperature", 1e-2)
        self.set_default_scaling("pressure", 1e-5)
        self.set_default_scaling("dens_mass_phase", 1e-3, index="Liq")
        self.set_default_scaling("dens_mass_phase", 1, index="Vap")
        # self.set_default_scaling('dens_mass_solvent', 1e-3)
        self.set_default_scaling("enth_mass_phase", 1e-5, index="Liq")
        self.set_default_scaling("enth_mass_phase", 1e-6, index="Vap")
        self.set_default_scaling("pressure_sat", 1e-5)
        self.set_default_scaling("cp_phase", 1e-3, index="Liq")
        self.set_default_scaling("cp_phase", 1e-3, index="Vap")
        self.set_default_scaling("dh_vap", 1e-6)
Beispiel #18
0
    def build(self):
        """Callable method for Block construction."""
        super(IdealStateBlockData, self).build()

        # Add state variables
        self.flow_mol_phase_comp = Var(
            self._params.phase_list,
            self._params.component_list,
            initialize=0.5,
            bounds=(1e-8, 100),
            doc='Phase-component molar flow rates [mol/s]')

        self.pressure = Var(initialize=101325,
                            bounds=(101325, 400000),
                            domain=NonNegativeReals,
                            doc='State pressure [Pa]')
        self.temperature = Var(initialize=298.15,
                               bounds=(298.15, 1000),
                               domain=NonNegativeReals,
                               doc='State temperature [K]')

        # Add supporting variables
        def flow_mol_phase(b, p):
            return sum(b.flow_mol_phase_comp[p, j]
                       for j in b._params.component_list)

        self.flow_mol_phase = Expression(self._params.phase_list,
                                         rule=flow_mol_phase,
                                         doc='Phase molar flow rates [mol/s]')

        def flow_mol(b):
            return sum(b.flow_mol_phase_comp[p, j]
                       for j in b._params.component_list
                       for p in b._params.phase_list)

        self.flow_mol = Expression(rule=flow_mol,
                                   doc='Total molar flowrate [mol/s]')

        def mole_frac_phase_comp(b, p, j):
            return b.flow_mol_phase_comp[p, j] / b.flow_mol_phase[p]

        self.mole_frac_phase_comp = Expression(self._params.phase_list,
                                               self._params.component_list,
                                               rule=mole_frac_phase_comp,
                                               doc='Phase mole fractions [-]')

        def mole_frac_comp(b, j):
            return (sum(b.flow_mol_phase_comp[p, j]
                        for p in b._params.phase_list) / b.flow_mol)

        self.mole_frac_comp = Expression(self._params.component_list,
                                         rule=mole_frac_comp,
                                         doc='Mixture mole fractions [-]')

        # Reaction Stoichiometry
        add_object_reference(self, "phase_equilibrium_list_ref",
                             self._params.phase_equilibrium_list)

        if (self.config.has_phase_equilibrium
                and self.config.defined_state is False):
            # Definition of equilibrium temperature for smooth VLE
            self._teq = Var(
                initialize=self.temperature.value,
                doc='Temperature for calculating phase equilibrium')
            self._t1 = Var(initialize=self.temperature.value,
                           doc='Intermediate temperature for calculating Teq')

            self.eps_1 = Param(default=0.01,
                               mutable=True,
                               doc='Smoothing parameter for Teq')
            self.eps_2 = Param(default=0.0005,
                               mutable=True,
                               doc='Smoothing parameter for Teq')

            # PSE paper Eqn 13
            def rule_t1(b):
                return b._t1 == 0.5 * (
                    b.temperature + b.temperature_bubble +
                    sqrt((b.temperature - b.temperature_bubble)**2 +
                         b.eps_1**2))

            self._t1_constraint = Constraint(rule=rule_t1)

            # PSE paper Eqn 14
            # TODO : Add option for supercritical extension
            def rule_teq(b):
                return b._teq == 0.5 * (b._t1 + b.temperature_dew - sqrt(
                    (b._t1 - b.temperature_dew)**2 + b.eps_2**2))

            self._teq_constraint = Constraint(rule=rule_teq)

            def rule_tr_eq(b, i):
                return b._teq / b._params.temperature_crit[i]

            self._tr_eq = Expression(self._params.component_list,
                                     rule=rule_tr_eq,
                                     doc='Component reduced temperatures [-]')

            def rule_equilibrium(b, i):
                return b.fug_vap[i] == b.fug_liq[i]

            self.equilibrium_constraint = Constraint(
                self._params.component_list, rule=rule_equilibrium)
    def build(self):
        '''
        Callable method for Block construction.
        '''
        super(PhysicalParameterData, self).build()

        self._state_block_class = SolidPhaseStateBlock

        # Create Phase object
        self.Sol = SolidPhase()

        # Create Component objects
        self.Fe2O3 = Component()
        self.Fe3O4 = Component()
        self.Al2O3 = Component()

        # -------------------------------------------------------------------------
        """ Pure solid component properties"""

        # Mol. weights of solid components - units = kg/mol. ref: NIST webbook
        mw_comp_dict = {'Fe2O3': 0.15969, 'Fe3O4': 0.231533, 'Al2O3': 0.10196}
        self.mw_comp = Param(
            self.component_list,
            mutable=False,
            initialize=mw_comp_dict,
            doc="Molecular weights of solid components [kg/mol]",
            units=pyunits.kg / pyunits.m**3)

        # Skeletal density of solid components - units = kg/m3. ref: NIST
        dens_mass_comp_skeletal_dict = {
            'Fe2O3': 5250,
            'Fe3O4': 5000,
            'Al2O3': 3987
        }
        self.dens_mass_comp_skeletal = Param(
            self.component_list,
            mutable=False,
            initialize=dens_mass_comp_skeletal_dict,
            doc='Skeletal density of solid components [kg/m3]',
            units=pyunits.kg / pyunits.m**3)

        # Ideal gas spec. heat capacity parameters(Shomate) of
        # components - ref: NIST webbook. Shomate equations from NIST.
        # Parameters A-E are used for cp calcs while A-H are used for enthalpy
        # calc.
        # 1e3*cp_comp = A + B*T + C*T^2 + D*T^3 + E/(T^2)
        # where T = Temperature (K)/1000, and cp_comp = (kJ/mol.K)
        # H_comp = H - H(298.15) = A*T + B*T^2/2 + C*T^3/3 +
        # D*T^4/4 - E/T + F - H where T = Temp (K)/1000 and H_comp = (kJ/mol)
        cp_param_dict = {
            ('Al2O3', 1): 102.4290,
            ('Al2O3', 2): 38.74980,
            ('Al2O3', 3): -15.91090,
            ('Al2O3', 4): 2.628181,
            ('Al2O3', 5): -3.007551,
            ('Al2O3', 6): -1717.930,
            ('Al2O3', 7): 146.9970,
            ('Al2O3', 8): -1675.690,
            ('Fe3O4', 1): 200.8320000,
            ('Fe3O4', 2): 1.586435e-7,
            ('Fe3O4', 3): -6.661682e-8,
            ('Fe3O4', 4): 9.452452e-9,
            ('Fe3O4', 5): 3.18602e-8,
            ('Fe3O4', 6): -1174.1350000,
            ('Fe3O4', 7): 388.0790000,
            ('Fe3O4', 8): -1120.8940000,
            ('Fe2O3', 1): 110.9362000,
            ('Fe2O3', 2): 32.0471400,
            ('Fe2O3', 3): -9.1923330,
            ('Fe2O3', 4): 0.9015060,
            ('Fe2O3', 5): 5.4336770,
            ('Fe2O3', 6): -843.1471000,
            ('Fe2O3', 7): 228.3548000,
            ('Fe2O3', 8): -825.5032000
        }
        self.cp_param = Param(self.component_list,
                              range(1, 10),
                              mutable=False,
                              initialize=cp_param_dict,
                              doc="Shomate equation heat capacity parameters")

        # Std. heat of formation of comp. - units = kJ/(mol comp) - ref: NIST
        enth_mol_form_comp_dict = {
            'Fe2O3': -825.5032,
            'Fe3O4': -1120.894,
            'Al2O3': -1675.690
        }
        self.enth_mol_form_comp = Param(
            self.component_list,
            mutable=False,
            initialize=enth_mol_form_comp_dict,
            doc="Component molar heats of formation [kJ/mol]",
            units=pyunits.kJ / pyunits.mol)

        # -------------------------------------------------------------------------
        """ Mixed solid properties"""
        # These are setup as fixed vars to allow for parameter estimation

        # Particle size
        self.particle_dia = Var(domain=Reals,
                                initialize=1.5e-3,
                                doc='Diameter of solid particles [m]',
                                units=pyunits.m)
        self.particle_dia.fix()

        # TODO -provide reference
        # Minimum fluidization velocity - EPAT value used for Davidson model
        self.velocity_mf = Var(domain=Reals,
                               initialize=0.039624,
                               doc='Velocity at minimum fluidization [m/s]',
                               units=pyunits.m / pyunits.s)
        self.velocity_mf.fix()

        # Minimum fluidization voidage - educated guess as rough
        # estimate from ergun equation results (0.4) are suspicious
        self.voidage_mf = Var(domain=Reals,
                              initialize=0.45,
                              doc='Voidage at minimum fluidization [-]',
                              units=pyunits.m**3 / pyunits.m**3)
        self.voidage_mf.fix()

        # Particle thermal conductivity
        self.therm_cond_sol = Var(
            domain=Reals,
            initialize=12.3e-3,
            doc='Thermal conductivity of solid particles [kJ/m.K.s]',
            units=pyunits.kJ / pyunits.m / pyunits.K / pyunits.s)
        self.therm_cond_sol.fix()
Beispiel #20
0
 def _temperature_bubble(self):
     self.temperature_bubble = Param(initialize=33.0,
                                     doc="Bubble point temperature (K)")
Beispiel #21
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """ """
    # Price by market and timepoint
    # Prices are allowed to be negative
    m.market_price = Param(m.MARKETS, m.TMPS, within=Reals)
Beispiel #22
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`CRBN_PRJS`                                                     |
    | | *Within*: :code:`PROJECTS`                                            |
    |                                                                         |
    | Two set of carbonaceous projects we need to track for the carbon cap.   |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Required Input Params                                                   |
    +=========================================================================+
    | | :code:`carbon_cap_zone`                                               |
    | | *Defined over*: :code:`CRBN_PRJS`                                     |
    | | *Within*: :code:`CARBON_CAP_ZONES`                                    |
    |                                                                         |
    | This param describes the carbon cap zone for each carbonaceous project. |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Derived Sets                                                            |
    +=========================================================================+
    | | :code:`CRBN_PRJS_BY_CARBON_CAP_ZONE`                                  |
    | | *Defined over*: :code:`CARBON_CAP_ZONES`                              |
    | | *Within*: :code:`CRBN_PRJS`                                           |
    |                                                                         |
    | Indexed set that describes the list of carbonaceous projects for each   |
    | carbon cap zone.                                                        |
    +-------------------------------------------------------------------------+
    | | :code:`CRBN_PRJ_OPR_TMPS`                                             |
    | | *Within*: :code:`PRJ_OPR_TMPS`                                        |
    |                                                                         |
    | Two-dimensional set that defines all project-timepoint combinations     |
    | when a carbonaceous project can be operational.                         |
    +-------------------------------------------------------------------------+

    """

    # Sets
    ###########################################################################

    m.CRBN_PRJS = Set(within=m.PROJECTS)

    # Input Params
    ###########################################################################

    m.carbon_cap_zone = Param(m.CRBN_PRJS, within=m.CARBON_CAP_ZONES)

    # Derived Sets
    ###########################################################################

    m.CRBN_PRJS_BY_CARBON_CAP_ZONE = Set(
        m.CARBON_CAP_ZONES,
        within=m.CRBN_PRJS,
        initialize=lambda mod, co2_z: subset_init_by_param_value(
            mod, "CRBN_PRJS", "carbon_cap_zone", co2_z),
    )

    m.CRBN_PRJ_OPR_TMPS = Set(
        within=m.PRJ_OPR_TMPS,
        initialize=lambda mod: [(p, tmp) for (p, tmp) in mod.PRJ_OPR_TMPS
                                if p in mod.CRBN_PRJS],
    )
 def _dens_mass(self):
     self.dens_mass = Param(initialize=self.params.dens_mass_default,
                            units=pyunits.kg / pyunits.m**3,
                            mutable=True,
                            doc="Mass density of flow")
Beispiel #24
0
def _solve_sigma_given_delta(var_est_object, solver, **kwds):
    """Solves the maximum likelihood formulation to determine the model variance from a
    given device variance.

       This method is not intended to be used by users directly

    Args:
        delta (float): the device variance squared 
    
        tee (bool,optional): flag to tell the optimizer whether to stream output
        to the terminal or not
    
        profile_time (bool,optional): flag to tell pyomo to time the construction and solution of the model. 
        Default False
    
        subset_lambdas (array_like,optional): Set of wavelengths to used in initialization problem 
        (Weifeng paper). Default all wavelengths.
        
        solver_opts (dict, optional): dictionary containing solver options for IPOPT

    Returns:

        residuals (float): the objective function value from the optimization
        
        variancesdict (dict): dictionary containing the model variance values
        
        stop_it (bool): boolean indicator showing whether no solution was found 
                            (True) or if there is a solution (False)
                            
        solver_results: Variance estimation model results, similar to VarianceEstimator 
                                    results from previous method

    """
    solver_opts = kwds.pop('solver_opts', dict())
    tee = kwds.pop('tee', False)
    set_A = kwds.pop('subset_lambdas', list())
    profile_time = kwds.pop('profile_time', False)
    delta = kwds.pop('delta', dict())
    species_list = kwds.pop('subset_components', None)

    model = var_est_object.model.clone()

    if not set_A:
        set_A = var_est_object._meas_lambdas

    if not var_est_object._sublist_components:
        list_components = []
        if species_list is None:
            list_components = [k for k in var_est_object._mixture_components]

        else:
            for k in species_list:
                if k in var_est_object._mixture_components:
                    list_components.append(k)
                else:
                    warnings.warn(
                        "Ignored {} since is not a mixture component of the model"
                        .format(k))

        var_est_object._sublist_components = list_components

    var_est_object._warn_if_D_negative()
    ntp = len(var_est_object._meas_times)
    obj = 0.0

    for t in var_est_object._meas_times:
        for l in set_A:
            D_bar = sum(var_est_object.model.C[t, k] *
                        var_est_object.model.S[l, k]
                        for k in var_est_object.component_set)
            obj += 0.5 / delta * (var_est_object.model.D[t, l] - D_bar)**2

    inlog = {k: 0 for k in var_est_object.component_set}
    var_est_object.model.eps = Param(initialize=1e-8)

    variancesdict = {k: 0 for k in var_est_object.component_set}

    for t in var_est_object._meas_times:
        for k in var_est_object.component_set:
            inlog[k] += ((var_est_object.model.C[t, k] -
                          var_est_object.model.Z[t, k])**2)

    for k in var_est_object.component_set:
        obj += 0.5 * ntp * log(inlog[k] / ntp + var_est_object.model.eps)

    var_est_object.model.init_objective = Objective(expr=obj)

    opt = SolverFactory(solver)

    for key, val in solver_opts.items():
        opt.options[key] = val
    try:
        solver_results = opt.solve(var_est_object.model,
                                   tee=tee,
                                   report_timing=profile_time)

        residuals = (value(var_est_object.model.init_objective))
        for t in var_est_object._allmeas_times:
            for k in var_est_object.component_set:
                variancesdict[k] += 1 / ntp * (
                    (value(var_est_object.model.C[t, k]) -
                     value(var_est_object.model.Z[t, k]))**2)

        print("Variances")
        for k in var_est_object.component_set:
            print(k, variancesdict[k])

        print("Parameter estimates")
        for k, v in var_est_object.model.P.items():
            print(k, v.value)

        stop_it = False

    except:
        print("FAILED AT THIS ITERATION")
        variancesdict = None
        residuals = 0
        stop_it = True
        solver_results = None
        for k, v in var_est_object.model.P.items():
            print(k, v.value)
        var_est_object.model = model
        for k, v in var_est_object.model.P.items():
            print(k, v.value)
    var_est_object.model.del_component('init_objective')
    var_est_object.model.del_component('eps')

    return residuals, variancesdict, stop_it, solver_results
Beispiel #25
0
def build_model():
    m = ConcreteModel()

    seed(1)  # Fix seed to generate same parameters and solution every time
    m.T_max = randint(10, 10)
    m.T = RangeSet(m.T_max)

    # Variables
    m.s = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='stock')
    m.x = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='purchased')
    m.c = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='cost')
    m.f = Var(m.T, domain=NonNegativeReals, bounds=(0, 10000), doc='feed')

    m.max_q_idx = RangeSet(m.T_max)

    # Randomly generated parameters
    m.D = Param(m.T, doc='demand',
                initialize=dict((t, randint(50, 100)) for t in m.T))
    m.alpha = Param(m.T, doc='storage cost',
                    initialize=dict((t, randint(5, 20)) for t in m.T))
    m.gamma = Param(m.T, doc='base buying cost',
                    initialize=dict((t, randint(10, 30)) for t in m.T))
    m.beta_B = Param(m.T, doc='bulk discount',
                     initialize=dict((t, randint(50, 500)/1000) for t in m.T))

    m.F_B_lo = Param(m.T, doc='bulk minimum purchase amount',
                     initialize=dict((t, randint(50, 100)) for t in m.T))

    m.beta_L = Param(m.T, m.max_q_idx,
                     initialize=dict(((t, q), randint(10, 999)/1000)
                                     for t in m.T for q in m.max_q_idx),
                     doc='long-term discount')
    m.F_L_lo = Param(m.T, m.max_q_idx,
                     initialize=dict(((t, q), randint(50, 100))
                                     for t in m.T for q in m.max_q_idx),
                     doc='long-term minimum purchase amount')

    # Contract choices 'standard', 'bulk' and long term contracts '0','1',...
    time_time_choices = [(t1, str(t2)) for t1, t2 in m.T * m.T if t2 <= m.T_max - t1]
    time_special_choices = [(t, s) for t in m.T for s in {'S', 'B', '0'}]
    m.contract_time_choices = Set(initialize=time_time_choices + time_special_choices)
    m.disjunct_choices = Set(
        initialize=['S', 'B', *[str(t) for t in range(m.T_max)]])
    m.disjuncts = Disjunct(m.contract_time_choices)
    m.Y = BooleanVar(m.contract_time_choices)
    for t, c in m.contract_time_choices:
        m.Y[t, c].associate_binary_var(m.disjuncts[t, c].indicator_var)

    # Create disjuncts for contracts in each timeset
    for t in m.T:
        m.disjuncts[t, 'S'].cost = Constraint(expr=m.c[t] == m.gamma[t]*m.x[t])

        m.disjuncts[t, 'B'].cost = Constraint(
            expr=m.c[t] == (1-m.beta_B[t])*m.gamma[t]*m.x[t])
        m.disjuncts[t, 'B'].amount = Constraint(
            expr=m.x[t] >= m.F_B_lo[t])

        m.disjuncts[t, '0'].c = Constraint(expr=0 <= m.c[t])

        for q in range(1, m.T_max-t+1):
            m.disjuncts[t, str(q)].t_idx = RangeSet(t, t+q)
            m.disjuncts[t, str(q)].cost = Constraint(m.disjuncts[t, str(q)].t_idx)
            m.disjuncts[t, str(q)].amount = Constraint(m.disjuncts[t, str(q)].t_idx)
            for t_ in m.disjuncts[t, str(q)].t_idx:
                m.disjuncts[t, str(q)].cost[t_] =\
                    m.c[t_] == (1-m.beta_L[t, q])*m.gamma[t]*m.x[t_]
                m.disjuncts[t, str(q)].amount[t_] =\
                    m.x[t_] >= m.F_L_lo[t, q]

    # Create disjunctions
    @m.Disjunction(m.T, xor=True)
    def disjunctions(m, t):
        return [m.disjuncts[t, 'S'], m.disjuncts[t, 'B'], m.disjuncts[t, '0'],
                *[m.disjuncts[t, str(q)] for q in range(1, m.T_max-t+1)]]

    # Connect the disjuncts indicator variables using logical expressions
    m.logical_blocks = Block(range(1, m.T_max+1))

    # Enforce absence of existing long-term contract
    m.logical_blocks[1].not_y_1_0 = LogicalConstraint(expr=~m.Y[1, '0'], doc="no pre-existing long-term contract")

    # Long-term contract implies '0'-disjunct in following timesteps
    for t in range(2, m.T_max+1):
        m.logical_blocks[t].equiv = LogicalConstraint(
            expr=m.Y[t, '0'].equivalent_to(lor(m.Y[t_, str(q)] for t_ in range(1, t) for q in range(t - t_, m.T_max - t_ + 1)))
        )

    # Objective function
    m.objective = Objective(expr=sum(m.alpha[t]*m.s[t]+m.c[t] for t in m.T))

    # Global constraints
    m.demand_satisfaction = Constraint(m.T)
    for t in m.T:
        m.demand_satisfaction[t] = m.f[t] >= m.D[t]

    m.material_balance = Constraint(m.T)
    for t in m.T:
        m.material_balance[t]=m.s[t] == (m.s[t-1] if t>1 else 0) + m.x[t] - m.f[t]

    return m
Beispiel #26
0
def build_eight_process_flowsheet():
    """Build flowsheet for the 8 process problem."""
    m = ConcreteModel(name='DuranEx3 Disjunctive')
    """Set declarations"""
    m.streams = RangeSet(2, 25, doc="process streams")
    m.units = RangeSet(1, 8, doc="process units")
    """Parameter and initial point declarations"""
    # FIXED COST INVESTMENT COEFF FOR PROCESS UNITS
    # Format: process #: cost
    fixed_cost = {1: 5, 2: 8, 3: 6, 4: 10, 5: 6, 6: 7, 7: 4, 8: 5}
    CF = m.CF = Param(m.units, initialize=fixed_cost)

    # VARIABLE COST COEFF FOR PROCESS UNITS - STREAMS
    # Format: stream #: cost
    variable_cost = {
        3: -10,
        5: -15,
        9: -40,
        19: 25,
        21: 35,
        25: -35,
        17: 80,
        14: 15,
        10: 15,
        2: 1,
        4: 1,
        18: -65,
        20: -60,
        22: -80
    }
    CV = m.CV = Param(m.streams, initialize=variable_cost, default=0)

    # initial point information for stream flows
    initX = {
        2: 2,
        3: 1.5,
        6: 0.75,
        7: 0.5,
        8: 0.5,
        9: 0.75,
        11: 1.5,
        12: 1.34,
        13: 2,
        14: 2.5,
        17: 2,
        18: 0.75,
        19: 2,
        20: 1.5,
        23: 1.7,
        24: 1.5,
        25: 0.5
    }
    """Variable declarations"""
    # FLOWRATES OF PROCESS STREAMS
    m.flow = Var(m.streams,
                 domain=NonNegativeReals,
                 initialize=initX,
                 bounds=(0, 10))
    # OBJECTIVE FUNCTION CONSTANT TERM
    CONSTANT = m.constant = Param(initialize=122.0)
    """Constraint definitions"""
    # INPUT-OUTPUT RELATIONS FOR process units 1 through 8
    m.use_unit1 = Disjunct()
    m.use_unit1.inout1 = Constraint(expr=exp(m.flow[3]) - 1 == m.flow[2])
    m.use_unit1.no_unit2_flow1 = Constraint(expr=m.flow[4] == 0)
    m.use_unit1.no_unit2_flow2 = Constraint(expr=m.flow[5] == 0)
    m.use_unit2 = Disjunct()
    m.use_unit2.inout2 = Constraint(expr=exp(m.flow[5] / 1.2) - 1 == m.flow[4])
    m.use_unit2.no_unit1_flow1 = Constraint(expr=m.flow[2] == 0)
    m.use_unit2.no_unit1_flow2 = Constraint(expr=m.flow[3] == 0)

    m.use_unit3 = Disjunct()
    m.use_unit3.inout3 = Constraint(expr=1.5 * m.flow[9] +
                                    m.flow[10] == m.flow[8])
    m.no_unit3 = Disjunct()
    m.no_unit3.no_unit3_flow1 = Constraint(expr=m.flow[9] == 0)
    m.no_unit3.flow_pass_through = Constraint(expr=m.flow[10] == m.flow[8])

    m.use_unit4 = Disjunct()
    m.use_unit4.inout4 = Constraint(expr=1.25 *
                                    (m.flow[12] + m.flow[14]) == m.flow[13])
    m.use_unit4.no_unit5_flow = Constraint(expr=m.flow[15] == 0)
    m.use_unit5 = Disjunct()
    m.use_unit5.inout5 = Constraint(expr=m.flow[15] == 2 * m.flow[16])
    m.use_unit5.no_unit4_flow1 = Constraint(expr=m.flow[12] == 0)
    m.use_unit5.no_unit4_flow2 = Constraint(expr=m.flow[14] == 0)
    m.no_unit4or5 = Disjunct()
    m.no_unit4or5.no_unit5_flow = Constraint(expr=m.flow[15] == 0)
    m.no_unit4or5.no_unit4_flow1 = Constraint(expr=m.flow[12] == 0)
    m.no_unit4or5.no_unit4_flow2 = Constraint(expr=m.flow[14] == 0)

    m.use_unit6 = Disjunct()
    m.use_unit6.inout6 = Constraint(expr=exp(m.flow[20] / 1.5) -
                                    1 == m.flow[19])
    m.use_unit6.no_unit7_flow1 = Constraint(expr=m.flow[21] == 0)
    m.use_unit6.no_unit7_flow2 = Constraint(expr=m.flow[22] == 0)
    m.use_unit7 = Disjunct()
    m.use_unit7.inout7 = Constraint(expr=exp(m.flow[22]) - 1 == m.flow[21])
    m.use_unit7.no_unit6_flow1 = Constraint(expr=m.flow[19] == 0)
    m.use_unit7.no_unit6_flow2 = Constraint(expr=m.flow[20] == 0)
    m.no_unit6or7 = Disjunct()
    m.no_unit6or7.no_unit7_flow1 = Constraint(expr=m.flow[21] == 0)
    m.no_unit6or7.no_unit7_flow2 = Constraint(expr=m.flow[22] == 0)
    m.no_unit6or7.no_unit6_flow = Constraint(expr=m.flow[19] == 0)
    m.no_unit6or7.no_unit6_flow2 = Constraint(expr=m.flow[20] == 0)

    m.use_unit8 = Disjunct()
    m.use_unit8.inout8 = Constraint(expr=exp(m.flow[18]) - 1 == m.flow[10] +
                                    m.flow[17])
    m.no_unit8 = Disjunct()
    m.no_unit8.no_unit8_flow1 = Constraint(expr=m.flow[10] == 0)
    m.no_unit8.no_unit8_flow2 = Constraint(expr=m.flow[17] == 0)
    m.no_unit8.no_unit8_flow3 = Constraint(expr=m.flow[18] == 0)

    # Mass balance equations
    m.massbal1 = Constraint(expr=m.flow[13] == m.flow[19] + m.flow[21])
    m.massbal2 = Constraint(expr=m.flow[17] == m.flow[9] + m.flow[16] +
                            m.flow[25])
    m.massbal3 = Constraint(expr=m.flow[11] == m.flow[12] + m.flow[15])
    m.massbal4 = Constraint(expr=m.flow[3] + m.flow[5] == m.flow[6] +
                            m.flow[11])
    m.massbal5 = Constraint(expr=m.flow[6] == m.flow[7] + m.flow[8])
    m.massbal6 = Constraint(expr=m.flow[23] == m.flow[20] + m.flow[22])
    m.massbal7 = Constraint(expr=m.flow[23] == m.flow[14] + m.flow[24])

    # process specifications
    m.specs1 = Constraint(expr=m.flow[10] <= 0.8 * m.flow[17])
    m.specs2 = Constraint(expr=m.flow[10] >= 0.4 * m.flow[17])
    m.specs3 = Constraint(expr=m.flow[12] <= 5 * m.flow[14])
    m.specs4 = Constraint(expr=m.flow[12] >= 2 * m.flow[14])

    # pure integer constraints
    m.use1or2 = Disjunction(expr=[m.use_unit1, m.use_unit2])
    m.use4or5maybe = Disjunction(
        expr=[m.use_unit4, m.use_unit5, m.no_unit4or5])
    m.use4or5 = Constraint(
        expr=m.use_unit4.indicator_var + m.use_unit5.indicator_var <= 1)
    m.use6or7maybe = Disjunction(
        expr=[m.use_unit6, m.use_unit7, m.no_unit6or7])
    m.use4implies6or7 = Constraint(expr=m.use_unit6.indicator_var +
                                   m.use_unit7.indicator_var -
                                   m.use_unit4.indicator_var == 0)
    m.use3maybe = Disjunction(expr=[m.use_unit3, m.no_unit3])
    m.either3ornot = Constraint(expr=m.use_unit3.indicator_var +
                                m.no_unit3.indicator_var == 1)
    m.use8maybe = Disjunction(expr=[m.use_unit8, m.no_unit8])
    m.use3implies8 = Constraint(
        expr=m.use_unit3.indicator_var - m.use_unit8.indicator_var <= 0)
    """Profit (objective) function definition"""
    m.profit = Objective(expr=sum(
        getattr(m, 'use_unit%s' % (unit, )).indicator_var * CF[unit]
        for unit in m.units) + sum(m.flow[stream] * CV[stream]
                                   for stream in m.streams) + CONSTANT,
                         sense=minimize)
    """Bound definitions"""
    # x (flow) upper bounds
    x_ubs = {3: 2, 5: 2, 9: 2, 10: 1, 14: 1, 17: 2, 19: 2, 21: 2, 25: 3}
    for i, x_ub in iteritems(x_ubs):
        m.flow[i].setub(x_ub)

    # # optimal solution
    # m.use_unit1.indicator_var = 0
    # m.use_unit2.indicator_var = 1
    # m.use_unit3.indicator_var = 0
    # m.no_unit3.indicator_var = 1
    # m.use_unit4.indicator_var = 1
    # m.use_unit5.indicator_var = 0
    # m.no_unit4or5.indicator_var = 0
    # m.use_unit6.indicator_var = 1
    # m.use_unit7.indicator_var = 0
    # m.no_unit6or7.indicator_var = 0
    # m.use_unit8.indicator_var = 1
    # m.no_unit8.indicator_var = 0

    return m
def create_model():
    """Create a :class:`pyomo.environ.AbstracModel` 
    for the diet problem"""

    m = AbstractModel("diet")

    #--------------------------
    #         Sets
    #--------------------------

    m.F = Set(doc="Foods. :math:`\\mathcal{F}`")
    m.N = Set(doc="Nutrients. :math:`\\mathcal{N}`")

    #--------------------------
    #       Parameters
    #--------------------------

    m.cost = Param(m.F,
                   within=pe.NonNegativeReals,
                   doc="""Cost of each food. 
        :math:`c_f \\geq 0`""")

    m.content = Param(m.F,
                      m.N,
                      within=pe.NonNegativeReals,
                      doc="""Amount of nutrient in each food. 
        :math:`a_{f,n} \\geq 0`""")

    m.min_intake = Param(m.N,
                         within=pe.NonNegativeReals,
                         default=0.0,
                         doc="""Lower bound on each nutrient. 
        :math:`y^{min}_n`""")

    m.max_intake = Param(m.N,
                         within=pe.NonNegativeReals,
                         default=infinity,
                         doc="""Upper bound on each nutrient. 
        :math:`y^{max}_n`""")

    m.volume = Param(m.F,
                     within=pe.PositiveReals,
                     doc="""Volume per serving of food. 
        :math:`v_f`""")

    m.max_volume = Param(within=pe.PositiveReals,
                         doc="""Maximum volume of food consumed. 
        :math:`v^{max}`""")

    #--------------------------
    #       Variables
    #--------------------------

    m.x = Var(m.F,
              within=pe.NonNegativeIntegers,
              doc="""Number of servings consumed of each food. 
        :math:`x_f \\geq 0`""")

    #--------------------------
    #       Expressions
    #--------------------------

    m.total_volume = Expression(rule=lambda m: pe.summation(m.volume, m.x),
                                doc="""Total volume of food consumed. \n
        .. math:: v^{tot} = \\sum_{f \\in \\mathcal{F}} 
            v_f \\cdot x_f""")

    m.intake = Expression(m.N,
                          rule=lambda m, n: sum(m.content[f, n] * m.x[f]
                                                for f in m.F),
                          doc="""Total intake of each nutrient. \n
        .. math:: y_n = \\sum_{f \\in \\mathcal{F}} 
            \\alpha_{f,n} \\cdot x_f""")

    #--------------------------
    #       Objective
    #--------------------------

    m.minimize_total_cost = Objective(
        rule=lambda m: pe.summation(m.cost, m.x),
        doc="""Minimize the cost of food that is consumed. \n
        .. math:: \\min_{x} \\sum_{f \\in \\mathcal{F}} c_f \\cdot x_f""")

    #--------------------------
    #       Constraints
    #--------------------------

    m.nutrient_limit = Constraint(
        m.N,
        rule=lambda m, n: inequality(m.min_intake[n], m.intake[n], m.
                                     max_intake[n]),
        doc="""Enforce upper and lower bounds on intake of each nutrient. \n
        .. math:: y^{min}_n \\leq y_n \\leq y^{max}_n""")

    m.volume_limit = Constraint(expr=m.total_volume <= m.max_volume,
                                doc="""Limit the volume of food consumed. \n
        .. math:: v^{tot} \\leq v^{max}""")

    return m
    def _make_flash_eq(self):
        def rule_total_mass_balance(b):
            return b.flow_mol_phase['Liq'] + \
                b.flow_mol_phase['Vap'] == b.flow_mol

        self.total_flow_balance = Constraint(rule=rule_total_mass_balance)

        def rule_comp_mass_balance(b, i):
            return b.flow_mol * b.mole_frac_comp[i] == \
                b.flow_mol_phase['Liq'] * b.mole_frac_phase_comp['Liq', i] + \
                b.flow_mol_phase['Vap'] * b.mole_frac_phase_comp['Vap', i]

        self.component_flow_balances = Constraint(self._params.component_list,
                                                  rule=rule_comp_mass_balance)

        def rule_mole_frac(b):
            return sum(b.mole_frac_phase_comp['Liq', i]
                       for i in b._params.component_list) -\
                sum(b.mole_frac_phase_comp['Vap', i]
                    for i in b._params.component_list) == 0

        self.sum_mole_frac = Constraint(rule=rule_mole_frac)

        if self.config.defined_state is False:
            # applied at outlet only
            self.sum_mole_frac_out = \
                Constraint(expr=1 == sum(self.mole_frac_comp[i]
                           for i in self._params.component_list))

        if self.config.has_phase_equilibrium:
            # Definition of equilibrium temperature for smooth VLE
            self._teq = Var(initialize=self.temperature.value,
                            doc='Temperature for calculating '
                            'phase equilibrium')
            self._t1 = Var(initialize=self.temperature.value,
                           doc='Intermediate temperature for calculating Teq')

            self.eps_1 = Param(default=0.01,
                               mutable=True,
                               doc='Smoothing parameter for Teq')
            self.eps_2 = Param(default=0.0005,
                               mutable=True,
                               doc='Smoothing parameter for Teq')

            # PSE paper Eqn 13
            def rule_t1(b):
                return b._t1 == 0.5 * \
                    (b.temperature + b.temperature_bubble +
                     sqrt((b.temperature - b.temperature_bubble)**2 +
                          b.eps_1**2))

            self._t1_constraint = Constraint(rule=rule_t1)

            # PSE paper Eqn 14
            # TODO : Add option for supercritical extension
            def rule_teq(b):
                return b._teq == 0.5 * (b._t1 + b.temperature_dew - sqrt(
                    (b._t1 - b.temperature_dew)**2 + b.eps_2**2))

            self._teq_constraint = Constraint(rule=rule_teq)

            def rule_tr_eq(b, i):
                return b._teq / b._params.temperature_crit[i]

            self._tr_eq = Expression(self._params.component_list,
                                     rule=rule_tr_eq,
                                     doc='Component reduced temperatures [-]')

            def rule_equilibrium(b, i):
                return b.fug_vap[i] == b.fug_liq[i]
            self.equilibrium_constraint = \
                Constraint(self._params.component_list, rule=rule_equilibrium)
Beispiel #29
0
    def test_clonedModel_soln(self):

        m_orig = fc.create_model()
        fc.initialize_model(m_orig, 100)

        m_orig.perturbed_a = Param(initialize=-0.25)
        m_orig.perturbed_H = Param(initialize=0.55)

        m_sipopt = sensitivity_calculation(
            'sipopt',
            m_orig, [m_orig.a, m_orig.H],
            [m_orig.perturbed_a, m_orig.perturbed_H],
            cloneModel=True)

        # verify cloned model has _SENSITIVITY_TOOLBOX_DATA block
        # and original model is untouched
        self.assertFalse(m_sipopt == m_orig)

        self.assertTrue(
            hasattr(m_sipopt, '_SENSITIVITY_TOOLBOX_DATA')
            and m_sipopt._SENSITIVITY_TOOLBOX_DATA.ctype is Block)

        self.assertFalse(hasattr(m_orig, '_SENSITIVITY_TOOLBOX_DATA'))
        self.assertFalse(hasattr(m_orig, 'b'))

        # verify variable declaration
        self.assertTrue(
            hasattr(m_sipopt._SENSITIVITY_TOOLBOX_DATA, 'a')
            and m_sipopt._SENSITIVITY_TOOLBOX_DATA.a.ctype is Var)
        self.assertTrue(
            hasattr(m_sipopt._SENSITIVITY_TOOLBOX_DATA, 'H')
            and m_sipopt._SENSITIVITY_TOOLBOX_DATA.H.ctype is Var)

        # verify suffixes
        self.assertTrue(
            hasattr(m_sipopt, 'sens_state_0')
            and m_sipopt.sens_state_0.ctype is Suffix and
            m_sipopt.sens_state_0[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H] == 2
            and m_sipopt.sens_state_0[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a]
            == 1)

        self.assertTrue(
            hasattr(m_sipopt, 'sens_state_1')
            and m_sipopt.sens_state_1.ctype is Suffix and
            m_sipopt.sens_state_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H] == 2
            and m_sipopt.sens_state_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a]
            == 1)

        self.assertTrue(
            hasattr(m_sipopt, 'sens_state_value_1')
            and m_sipopt.sens_state_value_1.ctype is Suffix and
            m_sipopt.sens_state_value_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.H]
            == 0.55 and
            m_sipopt.sens_state_value_1[m_sipopt._SENSITIVITY_TOOLBOX_DATA.a]
            == -0.25)

        self.assertTrue(
            hasattr(m_sipopt, 'sens_init_constr')
            and m_sipopt.sens_init_constr.ctype is Suffix
            and m_sipopt.sens_init_constr[
                m_sipopt._SENSITIVITY_TOOLBOX_DATA.paramConst[1]] == 1
            and m_sipopt.sens_init_constr[
                m_sipopt._SENSITIVITY_TOOLBOX_DATA.paramConst[2]] == 2)

        self.assertTrue(
            hasattr(m_sipopt, 'sens_sol_state_1')
            and m_sipopt.sens_sol_state_1.ctype is Suffix)
        self.assertAlmostEqual(m_sipopt.sens_sol_state_1[m_sipopt.F[15]],
                               -0.00102016765, 8)

        # These tests require way too much precision for something that
        # just needs to enforce that bounds are not active...
        self.assertTrue(
            hasattr(m_sipopt, 'sens_sol_state_1_z_L')
            and m_sipopt.sens_sol_state_1_z_L.ctype is Suffix)
        self.assertAlmostEqual(m_sipopt.sens_sol_state_1_z_L[m_sipopt.u[15]],
                               -2.181712e-09, 13)

        self.assertTrue(
            hasattr(m_sipopt, 'sens_sol_state_1_z_U')
            and m_sipopt.sens_sol_state_1_z_U.ctype is Suffix)
        self.assertAlmostEqual(m_sipopt.sens_sol_state_1_z_U[m_sipopt.u[15]],
                               6.580899e-09, 13)

        # verify deactivated constraints for cloned model
        self.assertFalse(m_sipopt.FDiffCon[0].active
                         and m_sipopt.FDiffCon[7.5].active
                         and m_sipopt.FDiffCon[15].active)

        self.assertFalse(m_sipopt.x_dot[0].active
                         and m_sipopt.x_dot[7.5].active
                         and m_sipopt.x_dot[15].active)

        # verify constraints on original model are still active
        self.assertTrue(m_orig.FDiffCon[0].active
                        and m_orig.FDiffCon[7.5].active
                        and m_orig.FDiffCon[15].active)

        self.assertTrue(m_orig.x_dot[0].active and m_orig.x_dot[7.5].active
                        and m_orig.x_dot[15].active)

        # verify solution
        # NOTE: This is the solution to the original problem,
        # not the result of any sensitivity update.
        self.assertAlmostEqual(value(m_sipopt.J), 0.0048956783, 8)
    def build(self):
        # Call UnitModel.build to setup dynamics
        super().build()

        self.scaling_factor = Suffix(direction=Suffix.EXPORT)

        if (len(self.config.property_package.phase_list) > 1
                or 'Liq' not in [p for p in self.config.property_package.phase_list]):
            raise ConfigurationError(
                "NF model only supports one liquid phase ['Liq'],"
                "the property package has specified the following phases {}"
                    .format([p for p in self.config.property_package.phase_list]))

        units_meta = self.config.property_package.get_metadata().get_derived_units

        # TODO: update IDAES such that solvent and solute lists are automatically created on the parameter block
        self.solvent_list = Set()
        self.solute_list = Set()
        for c in self.config.property_package.component_list:
            comp = self.config.property_package.get_component(c)
            try:
                if comp.is_solvent():
                    self.solvent_list.add(c)
                if comp.is_solute():
                    self.solute_list.add(c)
            except TypeError:
                raise ConfigurationError("NF model only supports one solvent and one or more solutes,"
                                         "the provided property package has specified a component '{}' "
                                         "that is not a solvent or solute".format(c))
        if len(self.solvent_list) > 1:
            raise ConfigurationError("NF model only supports one solvent component,"
                                     "the provided property package has specified {} solvent components"
                                     .format(len(self.solvent_list)))

        # Add unit parameters
        self.A_comp = Var(
            self.flowsheet().config.time,
            self.solvent_list,
            initialize=1e-12,
            bounds=(1e-18, 1e-6),
            domain=NonNegativeReals,
            units=units_meta('length')*units_meta('pressure')**-1*units_meta('time')**-1,
            doc='Solvent permeability coeff.')
        self.B_comp = Var(
            self.flowsheet().config.time,
            self.solute_list,
            initialize=1e-8,
            bounds=(1e-11, 1e-5),
            domain=NonNegativeReals,
            units=units_meta('length')*units_meta('time')**-1,
            doc='Solute permeability coeff.')
        self.sigma = Var(
            self.flowsheet().config.time,
            initialize=0.5,
            bounds=(1e-8, 1e6),
            domain=NonNegativeReals,
            units=pyunits.dimensionless,
            doc='Reflection coefficient')
        self.dens_solvent = Param(
            initialize=1000,
            units=units_meta('mass')*units_meta('length')**-3,
            doc='Pure water density')

        # Add unit variables
        self.flux_mass_phase_comp_in = Var(
            self.flowsheet().config.time,
            self.config.property_package.phase_list,
            self.config.property_package.component_list,
            initialize=1e-3,
            bounds=(1e-12, 1e6),
            units=units_meta('mass')*units_meta('length')**-2*units_meta('time')**-1,
            doc='Flux at feed inlet')
        self.flux_mass_phase_comp_out = Var(
            self.flowsheet().config.time,
            self.config.property_package.phase_list,
            self.config.property_package.component_list,
            initialize=1e-3,
            bounds=(1e-12, 1e6),
            units=units_meta('mass')*units_meta('length')**-2*units_meta('time')**-1,
            doc='Flux at feed outlet')
        self.avg_conc_mass_phase_comp_in = Var(
            self.flowsheet().config.time,
            self.config.property_package.phase_list,
            self.solute_list,
            initialize=1e-3,
            bounds=(1e-8, 1e6),
            domain=NonNegativeReals,
            units=units_meta('mass')*units_meta('length')**-3,
            doc='Average solute concentration at feed inlet')
        self.avg_conc_mass_phase_comp_out = Var(
            self.flowsheet().config.time,
            self.config.property_package.phase_list,
            self.solute_list,
            initialize=1e-3,
            bounds=(1e-8, 1e6),
            domain=NonNegativeReals,
            units=units_meta('mass')*units_meta('length')**-3,
            doc='Average solute concentration at feed outlet')
        self.area = Var(
            initialize=1,
            bounds=(1e-8, 1e6),
            domain=NonNegativeReals,
            units=units_meta('length') ** 2,
            doc='Membrane area')

        # Build control volume for feed side
        self.feed_side = ControlVolume0DBlock(default={
            "dynamic": False,
            "has_holdup": False,
            "property_package": self.config.property_package,
            "property_package_args": self.config.property_package_args})

        self.feed_side.add_state_blocks(
            has_phase_equilibrium=False)

        self.feed_side.add_material_balances(
            balance_type=self.config.material_balance_type,
            has_mass_transfer=True)

        self.feed_side.add_energy_balances(
            balance_type=self.config.energy_balance_type,
            has_enthalpy_transfer=True)

        self.feed_side.add_momentum_balances(
            balance_type=self.config.momentum_balance_type,
            has_pressure_change=self.config.has_pressure_change)

        # Add permeate block
        tmp_dict = dict(**self.config.property_package_args)
        tmp_dict["has_phase_equilibrium"] = False
        tmp_dict["parameters"] = self.config.property_package
        tmp_dict["defined_state"] = False  # permeate block is not an inlet
        self.properties_permeate = self.config.property_package.state_block_class(
            self.flowsheet().config.time,
            doc="Material properties of permeate",
            default=tmp_dict)

        # Add Ports
        self.add_inlet_port(name='inlet', block=self.feed_side)
        self.add_outlet_port(name='retentate', block=self.feed_side)
        self.add_port(name='permeate', block=self.properties_permeate)

        # References for control volume
        # pressure change
        if (self.config.has_pressure_change is True and
                self.config.momentum_balance_type != 'none'):
            self.deltaP = Reference(self.feed_side.deltaP)

        # mass transfer
        self.mass_transfer_phase_comp = Var(
            self.flowsheet().config.time,
            self.config.property_package.phase_list,
            self.config.property_package.component_list,
            initialize=1,
            bounds=(1e-8, 1e6),
            domain=NonNegativeReals,
            units=units_meta('mass')*units_meta('time')**-1,
            doc='Mass transfer to permeate')

        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Mass transfer term")
        def eq_mass_transfer_term(self, t, p, j):
            return self.mass_transfer_phase_comp[t, p, j] == -self.feed_side.mass_transfer_term[t, p, j]

        # NF performance equations
        @self.Expression(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Average flux expression")
        def flux_mass_phase_comp_avg(b, t, p, j):
            return 0.5 * (b.flux_mass_phase_comp_in[t, p, j] + b.flux_mass_phase_comp_out[t, p, j])

        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Permeate production")
        def eq_permeate_production(b, t, p, j):
            return (b.properties_permeate[t].get_material_flow_terms(p, j)
                    == b.area * b.flux_mass_phase_comp_avg[t, p, j])

        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Inlet water and salt flux")
        def eq_flux_in(b, t, p, j):
            prop_feed = b.feed_side.properties_in[t]
            prop_perm = b.properties_permeate[t]
            comp = self.config.property_package.get_component(j)
            if comp.is_solvent():
                return (b.flux_mass_phase_comp_in[t, p, j] == b.A_comp[t, j] * b.dens_solvent
                        * ((prop_feed.pressure - prop_perm.pressure)
                           - b.sigma[t] * (prop_feed.pressure_osm - prop_perm.pressure_osm)))
            elif comp.is_solute():
                return (b.flux_mass_phase_comp_in[t, p, j] == b.B_comp[t, j]
                        * (prop_feed.conc_mass_phase_comp[p, j] - prop_perm.conc_mass_phase_comp[p, j])
                        + ((1 - b.sigma[t]) * b.flux_mass_phase_comp_in[t, p, j]
                           * 1 / b.dens_solvent * b.avg_conc_mass_phase_comp_in[t, p, j])
                        )

        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Outlet water and salt flux")
        def eq_flux_out(b, t, p, j):
            prop_feed = b.feed_side.properties_out[t]
            prop_perm = b.properties_permeate[t]
            comp = self.config.property_package.get_component(j)
            if comp.is_solvent():
                return (b.flux_mass_phase_comp_out[t, p, j] == b.A_comp[t, j] * b.dens_solvent
                        * ((prop_feed.pressure - prop_perm.pressure)
                           - b.sigma[t] * (prop_feed.pressure_osm - prop_perm.pressure_osm)))
            elif comp.is_solute():
                return (b.flux_mass_phase_comp_out[t, p, j] == b.B_comp[t, j]
                        * (prop_feed.conc_mass_phase_comp[p, j] - prop_perm.conc_mass_phase_comp[p, j])
                        + ((1 - b.sigma[t]) * b.flux_mass_phase_comp_out[t, p, j]
                           * 1 / b.dens_solvent * b.avg_conc_mass_phase_comp_out[t, p, j])
                        )

        # Average concentration
        # COMMENT: Chen approximation of logarithmic average implemented
        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.solute_list,
                         doc="Average inlet concentration")
        def eq_avg_conc_in(b, t, p, j):
            prop_feed = b.feed_side.properties_in[t]
            prop_perm = b.properties_permeate[t]
            return (b.avg_conc_mass_phase_comp_in[t, p, j] ==
                    (prop_feed.conc_mass_phase_comp[p, j] * prop_perm.conc_mass_phase_comp[p, j] *
                     (prop_feed.conc_mass_phase_comp[p, j] + prop_perm.conc_mass_phase_comp[p, j])/2)**(1/3))

        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.solute_list,
                         doc="Average inlet concentration")
        def eq_avg_conc_out(b, t, p, j):
            prop_feed = b.feed_side.properties_out[t]
            prop_perm = b.properties_permeate[t]
            return (b.avg_conc_mass_phase_comp_out[t, p, j] ==
                    (prop_feed.conc_mass_phase_comp[p, j] * prop_perm.conc_mass_phase_comp[p, j] *
                     (prop_feed.conc_mass_phase_comp[p, j] + prop_perm.conc_mass_phase_comp[p, j])/2)**(1/3))

        # Feed and permeate-side connection
        @self.Constraint(self.flowsheet().config.time,
                         self.config.property_package.phase_list,
                         self.config.property_package.component_list,
                         doc="Mass transfer from feed to permeate")
        def eq_connect_mass_transfer(b, t, p, j):
            return (b.properties_permeate[t].get_material_flow_terms(p, j)
                    == -b.feed_side.mass_transfer_term[t, p, j])

        @self.Constraint(self.flowsheet().config.time,
                         doc="Enthalpy transfer from feed to permeate")
        def eq_connect_enthalpy_transfer(b, t):
            return (b.properties_permeate[t].get_enthalpy_flow_terms('Liq')
                    == -b.feed_side.enthalpy_transfer[t])

        @self.Constraint(self.flowsheet().config.time,
                         doc="Isothermal assumption for permeate")
        def eq_permeate_isothermal(b, t):
            return b.feed_side.properties_out[t].temperature == \
                   b.properties_permeate[t].temperature