Exemple #1
0
 def test_empty_singleton(self):
     a = Constraint()
     a.construct()
     #
     # Even though we construct a SimpleConstraint,
     # if it is not initialized that means it is "empty"
     # and we should encounter errors when trying to access the
     # _ConstraintData interface methods until we assign
     # something to the constraint.
     #
     self.assertEqual(a._constructed, True)
     self.assertEqual(len(a), 0)
     try:
         a()
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.body
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.lower
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.upper
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.equality
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.strict_lower
         self.fail("Component is empty")
     except ValueError:
         pass
     try:
         a.strict_upper
         self.fail("Component is empty")
     except ValueError:
         pass
     x = Var(initialize=1.0)
     x.construct()
     a.set_value((0, x, 2))
     self.assertEqual(len(a), 1)
     self.assertEqual(a(), 1)
     self.assertEqual(a.body(), 1)
     self.assertEqual(a.lower(), 0)
     self.assertEqual(a.upper(), 2)
     self.assertEqual(a.equality, False)
     self.assertEqual(a.strict_lower, False)
     self.assertEqual(a.strict_upper, False)
Exemple #2
0
 def test_unconstructed_singleton(self):
     a = Constraint()
     self.assertEqual(a._constructed, False)
     self.assertEqual(len(a), 0)
     try:
         a()
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.body
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.lower
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.upper
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.equality
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.strict_lower
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     try:
         a.strict_upper
         self.fail("Component is unconstructed")
     except ValueError:
         pass
     x = Var(initialize=1.0)
     x.construct()
     a.construct()
     a.set_value((0, x, 2))
     self.assertEqual(len(a), 1)
     self.assertEqual(a(), 1)
     self.assertEqual(a.body(), 1)
     self.assertEqual(a.lower(), 0)
     self.assertEqual(a.upper(), 2)
     self.assertEqual(a.equality, False)
     self.assertEqual(a.strict_lower, False)
     self.assertEqual(a.strict_upper, False)
Exemple #3
0
 def Xtest_list_domain_bad_missing(self):
     with self.assertRaises(ValueError) as cm:
         self.model = ConcreteModel()
         self.model.y = Var([1, 2], within=[1, 4, 5])
Exemple #4
0
def add_model_components(m, d, scenario_directory, subproblem, stage):
    """
    The following Pyomo model components are defined in this module:

    +-------------------------------------------------------------------------+
    | Sets                                                                    |
    +=========================================================================+
    | | :code:`DR`                                                            |
    |                                                                         |
    | The set of projects of the :code:`dr` operational type.                 |
    +-------------------------------------------------------------------------+
    | | :code:`DR_OPR_TMPS`                                                   |
    |                                                                         |
    | Two-dimensional set with projects of the :code:`dr`                     |
    | operational type and their operational timepoints.                      |
    +-------------------------------------------------------------------------+
    | | :code:`DR_OPR_HRZS`                                                   |
    |                                                                         |
    | Two-dimensional set with projects of the :code:`dr`                     |
    | operational type and their operational horizons.                        |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Variables                                                               |
    +=========================================================================+
    | | :code:`DR_Shift_Up_MW`                                                |
    | | *Defined over*: :code:`DR_OPR_TMPS`                                   |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Load added (in MW) in each operational timepoint.                       |
    +-------------------------------------------------------------------------+
    | | :code:`DR_Shift_Down_MW`                                              |
    | | *Defined over*: :code:`DR_OPR_TMPS`                                   |
    | | *Within*: :code:`NonNegativeReals`                                    |
    |                                                                         |
    | Load removed (in MW) in each operational timepoint.                     |
    +-------------------------------------------------------------------------+

    |

    +-------------------------------------------------------------------------+
    | Constraints                                                             |
    +=========================================================================+
    | | :code:`DR_Max_Shift_Up_Constraint`                                    |
    | | *Defined over*: :code:`DR_OPR_TMPS`                                   |
    |                                                                         |
    | Limits the added load to the available power capacity.                  |
    +-------------------------------------------------------------------------+
    | | :code:`DR_Max_Shift_Down_Constraint`                                  |
    | | *Defined over*: :code:`DR_OPR_TMPS`                                   |
    |                                                                         |
    | Limits the removed load to the available power capacity.                |
    +-------------------------------------------------------------------------+
    | | :code:`DR_Energy_Balance_Constraint`                                  |
    | | *Defined over*: :code:`DR_OPR_HRZS`                                   |
    |                                                                         |
    | Ensures no energy losses or gains when shifting load within the horizon.|
    +-------------------------------------------------------------------------+
    | | :code:`DR_Energy_Budget_Constraint`                                   |
    | | *Defined˚ over*: :code:`DR_OPR_HRZS`                                  |
    |                                                                         |
    | Total energy that can be shifted on each horizon should be less than    |
    | or equal to budget.                                                     |
    +-------------------------------------------------------------------------+

    """

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

    m.DR = Set(
        within=m.PROJECTS,
        initialize=lambda mod: subset_init_by_param_value(
            mod, "PROJECTS", "operational_type", "dr"),
    )

    m.DR_OPR_TMPS = Set(
        dimen=2,
        within=m.PRJ_OPR_TMPS,
        initialize=lambda mod: list(
            set((g, tmp) for (g, tmp) in mod.PRJ_OPR_TMPS if g in mod.DR)),
    )

    m.DR_OPR_HRZS = Set(
        dimen=2,
        initialize=lambda mod: list(
            set((g, mod.horizon[tmp, mod.balancing_type_project[g]])
                for (g, tmp) in mod.PRJ_OPR_TMPS if g in mod.DR)),
    )

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

    m.DR_Shift_Up_MW = Var(m.DR_OPR_TMPS, within=NonNegativeReals)

    m.DR_Shift_Down_MW = Var(m.DR_OPR_TMPS, within=NonNegativeReals)

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

    m.DR_Max_Shift_Up_Constraint = Constraint(m.DR_OPR_TMPS,
                                              rule=max_shift_up_rule)

    m.DR_Max_Shift_Down_Constraint = Constraint(m.DR_OPR_TMPS,
                                                rule=max_shift_down_rule)

    m.DR_Energy_Balance_Constraint = Constraint(m.DR_OPR_HRZS,
                                                rule=energy_balance_rule)

    m.DR_Energy_Budget_Constraint = Constraint(m.DR_OPR_HRZS,
                                               rule=energy_budget_rule)
Exemple #5
0
    def build(self):
        super(ReactionBlockData, self).build()

        self.reaction_rate = Var(["r1", "r2"])

        self.dh_rxn = {"r1": 10, "r2": 20, "e1": 30, "e2": 40}
Exemple #6
0
 def b3(b3, i, j, k):
     b3.v = Var()
     b3.v1 = Var(m.d1_3)
     b3.v2 = Var(m.d1_1, m.d1_2)
     b3.vn = Var(m.d1_1, m.dn, m.d2)
Exemple #7
0
 def b1(b1, i):
     b1.v = Var()
     b1.v1 = Var(m.d1_3)
     b1.v2 = Var(m.d1_1, m.d1_2)
     b1.vn = Var(m.dn, m.d1_2)
Exemple #8
0
    def test_generate_cuid_string_map(self):
        model = Block(concrete=True)
        model.x = Var()
        model.y = Var([1, 2])
        model.V = Var([('a', 'b'), (1, '2'), (3, 4)])
        model.b = Block(concrete=True)
        model.b.z = Var([1, '2'])
        setattr(model.b, '.H', Var(['a', 2]))
        model.B = Block(['a', 2], concrete=True)
        setattr(model.B['a'], '.k', Var())
        model.B[2].b = Block()
        model.B[2].b.x = Var()
        model.add_component('c tuple', Constraint(Any))
        model.component('c tuple')[(1, )] = model.x >= 0

        cuids = (
            ComponentUID.generate_cuid_string_map(model, repr_version=1),
            ComponentUID.generate_cuid_string_map(model),
        )
        self.assertEqual(len(cuids[0]), 29)
        self.assertEqual(len(cuids[1]), 29)
        for obj in [
                model, model.x, model.y, model.y_index, model.y[1], model.y[2],
                model.V, model.V_index, model.V['a', 'b'], model.V[1, '2'],
                model.V[3, 4], model.b, model.b.z, model.b.z_index,
                model.b.z[1], model.b.z['2'],
                getattr(model.b, '.H'),
                getattr(model.b, '.H_index'),
                getattr(model.b, '.H')['a'],
                getattr(model.b,
                        '.H')[2], model.B, model.B_index, model.B['a'],
                getattr(model.B['a'],
                        '.k'), model.B[2], model.B[2].b, model.B[2].b.x,
                model.component('c tuple')[(1, )]
        ]:
            self.assertEqual(ComponentUID(obj).get_repr(1), cuids[0][obj])
            self.assertEqual(repr(ComponentUID(obj)), cuids[1][obj])

        cuids = (
            ComponentUID.generate_cuid_string_map(model,
                                                  descend_into=False,
                                                  repr_version=1),
            ComponentUID.generate_cuid_string_map(model, descend_into=False),
        )
        self.assertEqual(len(cuids[0]), 18)
        self.assertEqual(len(cuids[1]), 18)
        for obj in [
                model, model.x, model.y, model.y_index, model.y[1], model.y[2],
                model.V, model.V_index, model.V['a', 'b'], model.V[1, '2'],
                model.V[3, 4], model.b, model.B, model.B_index, model.B['a'],
                model.B[2],
                model.component('c tuple')[(1, )]
        ]:
            self.assertEqual(ComponentUID(obj).get_repr(1), cuids[0][obj])
            self.assertEqual(repr(ComponentUID(obj)), cuids[1][obj])

        cuids = (
            ComponentUID.generate_cuid_string_map(model,
                                                  ctype=Var,
                                                  repr_version=1),
            ComponentUID.generate_cuid_string_map(model, ctype=Var),
        )
        self.assertEqual(len(cuids[0]), 22)
        self.assertEqual(len(cuids[1]), 22)
        for obj in [
                model, model.x, model.y, model.y[1], model.y[2], model.V,
                model.V['a', 'b'], model.V[1, '2'], model.V[3, 4], model.b,
                model.b.z, model.b.z[1], model.b.z['2'],
                getattr(model.b, '.H'),
                getattr(model.b, '.H')['a'],
                getattr(model.b, '.H')[2], model.B, model.B['a'],
                getattr(model.B['a'],
                        '.k'), model.B[2], model.B[2].b, model.B[2].b.x
        ]:
            self.assertEqual(ComponentUID(obj).get_repr(1), cuids[0][obj])
            self.assertEqual(repr(ComponentUID(obj)), cuids[1][obj])

        cuids = (
            ComponentUID.generate_cuid_string_map(model,
                                                  ctype=Var,
                                                  descend_into=False,
                                                  repr_version=1),
            ComponentUID.generate_cuid_string_map(model,
                                                  ctype=Var,
                                                  descend_into=False),
        )
        self.assertEqual(len(cuids[0]), 9)
        self.assertEqual(len(cuids[1]), 9)
        for obj in [
                model, model.x, model.y, model.y[1], model.y[2], model.V,
                model.V['a', 'b'], model.V[1, '2'], model.V[3, 4]
        ]:
            self.assertEqual(ComponentUID(obj).get_repr(1), cuids[0][obj])
            self.assertEqual(repr(ComponentUID(obj)), cuids[1][obj])
Exemple #9
0
 def test_var_value_None(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 1))
     m.obj = Objective(expr=m.x)
     SolverFactory('multistart').solve(m)
Exemple #10
0
 def test_no_obj(self):
     m = ConcreteModel()
     m.x = Var()
     with self.assertRaisesRegexp(RuntimeError, "no active objective"):
         SolverFactory('multistart').solve(m)
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 x_ubs.items():
        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
Exemple #12
0
    def test_check_productexpression(self):
        m = self.m
        m.p = Param(initialize=5)
        m.mp = Param(initialize=5, mutable=True)
        m.y = Var()
        m.z = Var()
        t = IndexTemplate(m.t)

        # Check multiplication by constant
        e = 5 * m.dv[t] == m.v[t]
        temp = _check_productexpression(e, 0)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)

        e = m.v[t] == 5 * m.dv[t]
        temp = _check_productexpression(e, 1)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)

        # Check multiplication by fixed param
        e = m.p * m.dv[t] == m.v[t]
        temp = _check_productexpression(e, 0)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)

        e = m.v[t] == m.p * m.dv[t]
        temp = _check_productexpression(e, 1)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)

        # Check multiplication by mutable param
        e = m.mp * m.dv[t] == m.v[t]
        temp = _check_productexpression(e, 0)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(m.mp, temp[1].arg(1))      # Reciprocal
        self.assertIs(e.arg(1), temp[1].arg(0))

        e = m.v[t] == m.mp * m.dv[t]
        temp = _check_productexpression(e, 1)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(m.mp, temp[1].arg(1))      # Reciprocal
        self.assertIs(e.arg(0), temp[1].arg(0))

        # Check multiplication by var
        e = m.y * m.dv[t] / m.z == m.v[t]
        temp = _check_productexpression(e, 0)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(e.arg(1), temp[1].arg(0).arg(0))
        self.assertIs(m.z,        temp[1].arg(0).arg(1))

        e = m.v[t] == m.y * m.dv[t] / m.z
        temp = _check_productexpression(e, 1)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(e.arg(0), temp[1].arg(0).arg(0))
        self.assertIs(m.z, temp[1].arg(0).arg(1))

        # Check having the DerivativeVar in the denominator
        e = m.y / (m.dv[t] * m.z) == m.mp
        temp = _check_productexpression(e, 0)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(m.y,        temp[1].arg(0))
        self.assertIs(e.arg(1), temp[1].arg(1).arg(0))

        e = m.mp == m.y / (m.dv[t] * m.z)
        temp = _check_productexpression(e, 1)
        self.assertIs(m.dv, temp[0]._base)
        self.assertIs(type(temp[1]), EXPR.DivisionExpression)
        self.assertIs(m.y,        temp[1].arg(0))
        self.assertIs(e.arg(0), temp[1].arg(1).arg(0))
        
        # Check expression with no DerivativeVar
        e = m.v[t] * m.y / m.z == m.v[t] * m.y / m.z
        temp = _check_productexpression(e, 0)
        self.assertIsNone(temp)
        temp = _check_productexpression(e, 1)
        self.assertIsNone(temp)
Exemple #13
0
    def test_sim_initialization_multi_index2(self):

        m = self.m
        m.s2 = Set(initialize=[(1, 1), (2, 2)])
        m.w1 = Var(m.t, m.s2)
        m.dw1 = DerivativeVar(m.w1)

        m.w2 = Var(m.s2, m.t)
        m.dw2 = DerivativeVar(m.w2)

        m.w3 = Var([0, 1], m.t, m.s2)
        m.dw3 = DerivativeVar(m.w3)

        t = IndexTemplate(m.t)
        
        def _deq1(m, t, i, j):
            return m.dw1[t, i, j] == m.w1[t, i, j]
        m.deq1 = Constraint(m.t, m.s2, rule=_deq1)

        def _deq2(m, *idx):
            return m.dw2[idx] == m.w2[idx]
        m.deq2 = Constraint(m.s2, m.t, rule=_deq2)

        def _deq3(m, i, t, j, k):
            return m.dw3[i, t, j, k] == m.w1[t, j, k] + m.w2[j, k, t]
        m.deq3 = Constraint([0, 1], m.t, m.s2, rule=_deq3)

        mysim = Simulator(m)

        self.assertIs(mysim._contset, m.t)
        self.assertEqual(len(mysim._diffvars), 8)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w1[t, 2, 2]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[1, 1, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[2, 2, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[0, t, 1, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[1, t, 2, 2]) in mysim._diffvars)

        self.assertEqual(len(mysim._derivlist), 8)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 1, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 2, 2]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[1, 1, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[2, 2, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[0, t, 1, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[1, t, 2, 2]) in mysim._derivlist)

        self.assertEqual(len(mysim._templatemap), 4)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1, 1]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w1[t, 2, 2]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[1, 1, t]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[2, 2, t]) in mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[0, t, 1, 1]) in
                         mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[1, t, 2, 2]) in
                         mysim._templatemap)

        self.assertEqual(len(mysim._rhsdict), 8)
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1, 1])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 2, 2])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw2[1, 1, t])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw2[2, 2, t])], Param))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw3[0, t, 1, 1])],
            EXPR.SumExpression))
        self.assertTrue(isinstance(
            mysim._rhsdict[_GetItemIndexer(m.dw3[1, t, 2, 2])],
            EXPR.SumExpression))
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1, 1])].name,
                         'w1[{t},1,1]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 2, 2])].name,
                         'w1[{t},2,2]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw2[1, 1, t])].name,
                         'w2[1,1,{t}]')
        self.assertEqual(mysim._rhsdict[_GetItemIndexer(m.dw2[2, 2, t])].name,
                         'w2[2,2,{t}]')

        self.assertEqual(len(mysim._rhsfun(0, [0] * 8)), 8)
        self.assertIsNone(mysim._tsim)
        self.assertIsNone(mysim._simsolution)

        m.del_component('deq1')
        m.del_component('deq1_index')
        m.del_component('deq2')
        m.del_component('deq2_index')
        m.del_component('deq3')
        m.del_component('deq3_index')
Exemple #14
0
    def test_sim_initialization_multi_index(self):

        m = self.m
        m.w1 = Var(m.t, m.s)
        m.dw1 = DerivativeVar(m.w1)

        m.w2 = Var(m.s, m.t)
        m.dw2 = DerivativeVar(m.w2)

        m.w3 = Var([0, 1], m.t, m.s)
        m.dw3 = DerivativeVar(m.w3)

        t = IndexTemplate(m.t)
        
        def _deq1(m, t, s):
            return m.dw1[t, s] == m.w1[t, s]
        m.deq1 = Constraint(m.t, m.s, rule=_deq1)

        def _deq2(m, s, t):
            return m.dw2[s, t] == m.w2[s, t]
        m.deq2 = Constraint(m.s, m.t, rule=_deq2)

        def _deq3(m, i, t, s):
            return m.dw3[i, t, s] == m.w1[t, s] + m.w2[i + 1, t]
        m.deq3 = Constraint([0, 1], m.t, m.s, rule=_deq3)

        mysim = Simulator(m)

        self.assertIs(mysim._contset, m.t)
        self.assertEqual(len(mysim._diffvars), 12)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w1[t, 3]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[1, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w2[3, t]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[0, t, 1]) in mysim._diffvars)
        self.assertTrue(_GetItemIndexer(m.w3[1, t, 3]) in mysim._diffvars)

        self.assertEqual(len(mysim._derivlist), 12)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw1[t, 3]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[1, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw2[3, t]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[0, t, 1]) in mysim._derivlist)
        self.assertTrue(_GetItemIndexer(m.dw3[1, t, 3]) in mysim._derivlist)

        self.assertEqual(len(mysim._templatemap), 6)
        self.assertTrue(_GetItemIndexer(m.w1[t, 1]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w1[t, 3]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[1, t]) in mysim._templatemap)
        self.assertTrue(_GetItemIndexer(m.w2[3, t]) in mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[0, t, 1]) in mysim._templatemap)
        self.assertFalse(_GetItemIndexer(m.w3[1, t, 3]) in mysim._templatemap)

        self.assertEqual(len(mysim._rhsdict), 12)
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1])], Param))
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw1[t, 3])], Param))
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw2[1, t])], Param))
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw2[3, t])], Param))
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw3[0, t, 1])],
                       EXPR.SumExpression))
        self.assertTrue(
            isinstance(mysim._rhsdict[_GetItemIndexer(m.dw3[1, t, 3])],
                       EXPR.SumExpression))
        self.assertEqual(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 1])].name, 'w1[{t},1]')
        self.assertEqual(
            mysim._rhsdict[_GetItemIndexer(m.dw1[t, 3])].name, 'w1[{t},3]')
        self.assertEqual(
            mysim._rhsdict[_GetItemIndexer(m.dw2[1, t])].name, 'w2[1,{t}]')
        self.assertEqual(
            mysim._rhsdict[_GetItemIndexer(m.dw2[3, t])].name, 'w2[3,{t}]')

        self.assertEqual(len(mysim._rhsfun(0, [0] * 12)), 12)
        self.assertIsNone(mysim._tsim)
        self.assertIsNone(mysim._simsolution)

        m.del_component('deq1')
        m.del_component('deq1_index')
        m.del_component('deq2')
        m.del_component('deq2_index')
        m.del_component('deq3')
        m.del_component('deq3_index')
Exemple #15
0
    def test_separable_diffeq_case6(self):

        m = self.m
        m.w = Var(m.t, m.s)
        m.dw = DerivativeVar(m.w)
        m.p = Param(initialize=5)
        m.mp = Param(initialize=5, mutable=True)
        m.y = Var()
        
        t = IndexTemplate(m.t)

        def _deqv(m, i):
            return m.v[i]**2 + m.v[i] == m.dv[i] + m.y
        m.deqv = Constraint(m.t, rule=_deqv)

        def _deqw(m, i, j):
            return m.w[i, j]**2 + m.w[i, j] == m.y + m.dw[i, j]
        m.deqw = Constraint(m.t, m.s, rule=_deqw)

        mysim = Simulator(m)

        self.assertEqual(len(mysim._diffvars), 4)
        self.assertEqual(mysim._diffvars[0], _GetItemIndexer(m.v[t]))
        self.assertEqual(mysim._diffvars[1], _GetItemIndexer(m.w[t, 1]))
        self.assertEqual(mysim._diffvars[2], _GetItemIndexer(m.w[t, 2]))
        self.assertEqual(len(mysim._derivlist), 4)
        self.assertEqual(mysim._derivlist[0], _GetItemIndexer(m.dv[t]))
        self.assertEqual(mysim._derivlist[1], _GetItemIndexer(m.dw[t, 1]))
        self.assertEqual(mysim._derivlist[2], _GetItemIndexer(m.dw[t, 2]))
        self.assertEqual(len(mysim._rhsdict), 4)
        m.del_component('deqv')
        m.del_component('deqw')
        m.del_component('deqv_index')
        m.del_component('deqw_index')

        def _deqv(m, i):
            return m.v[i]**2 + m.v[i] == m.mp + m.dv[i]
        m.deqv = Constraint(m.t, rule=_deqv)

        def _deqw(m, i, j):
            return m.w[i, j]**2 + m.w[i, j] == m.dw[i, j] + m.p
        m.deqw = Constraint(m.t, m.s, rule=_deqw)

        mysim = Simulator(m)

        self.assertEqual(len(mysim._diffvars), 4)
        self.assertEqual(mysim._diffvars[0], _GetItemIndexer(m.v[t]))
        self.assertEqual(mysim._diffvars[1], _GetItemIndexer(m.w[t, 1]))
        self.assertEqual(mysim._diffvars[2], _GetItemIndexer(m.w[t, 2]))
        self.assertEqual(len(mysim._derivlist), 4)
        self.assertEqual(mysim._derivlist[0], _GetItemIndexer(m.dv[t]))
        self.assertEqual(mysim._derivlist[1], _GetItemIndexer(m.dw[t, 1]))
        self.assertEqual(mysim._derivlist[2], _GetItemIndexer(m.dw[t, 2]))
        self.assertEqual(len(mysim._rhsdict), 4)
        m.del_component('deqv')
        m.del_component('deqw')
        m.del_component('deqv_index')
        m.del_component('deqw_index')
        m.del_component('w')
        m.del_component('dw')
        m.del_component('p')
        m.del_component('mp')
        m.del_component('y')
Exemple #16
0
def define_state(b):
    b.temperature = Var(initialize=100)
    b.mole_frac_phase_comp = Var(b.params.phase_list,
                                 b.params.component_list,
                                 initialize=0.5)
Exemple #17
0
def define_state(b):
    # FcTP formulation always requires a flash, so set flag to True
    # TODO: should have some checking to make sure developers implement this properly
    b.always_flash = True

    units = b.params.get_metadata().derived_units
    # Get bounds and initial values from config args
    f_bounds, f_init = get_bounds_from_config(b, "flow_mol_comp",
                                              units["flow_mole"])
    t_bounds, t_init = get_bounds_from_config(b, "temperature",
                                              units["temperature"])
    p_bounds, p_init = get_bounds_from_config(b, "pressure", units["pressure"])

    # Add state variables
    b.flow_mol_comp = Var(b.params.component_list,
                          initialize=f_init,
                          domain=NonNegativeReals,
                          bounds=f_bounds,
                          doc=' Component molar flowrate',
                          units=units["flow_mole"])
    b.pressure = Var(initialize=p_init,
                     domain=NonNegativeReals,
                     bounds=p_bounds,
                     doc='State pressure',
                     units=units["pressure"])
    b.temperature = Var(initialize=t_init,
                        domain=NonNegativeReals,
                        bounds=t_bounds,
                        doc='State temperature',
                        units=units["temperature"])

    # Add supporting variables
    b.flow_mol = Expression(expr=sum(b.flow_mol_comp[j]
                                     for j in b.params.component_list),
                            doc="Total molar flowrate")

    if f_init is None:
        fp_init = None
    else:
        fp_init = f_init / len(b.params.phase_list)

    b.flow_mol_phase = Var(b.params.phase_list,
                           initialize=fp_init,
                           domain=NonNegativeReals,
                           bounds=f_bounds,
                           doc='Phase molar flow rates',
                           units=units["flow_mole"])

    b.mole_frac_comp = Var(b.params.component_list,
                           bounds=(0, None),
                           initialize=1 / len(b.params.component_list),
                           doc='Mixture mole fractions',
                           units=None)

    b.mole_frac_phase_comp = Var(b.params._phase_component_set,
                                 initialize=1 / len(b.params.component_list),
                                 bounds=(0, None),
                                 doc='Phase mole fractions',
                                 units=None)

    b.phase_frac = Var(b.params.phase_list,
                       initialize=1 / len(b.params.phase_list),
                       bounds=(0, None),
                       doc='Phase fractions',
                       units=None)

    # Add supporting constraints
    def rule_mole_frac_comp(b, j):
        if len(b.params.component_list) > 1:
            return b.flow_mol_comp[j] == b.mole_frac_comp[j] * sum(
                b.flow_mol_comp[k] for k in b.params.component_list)
        else:
            return b.mole_frac_comp[j] == 1

    b.mole_frac_comp_eq = Constraint(b.params.component_list,
                                     rule=rule_mole_frac_comp)

    if len(b.params.phase_list) == 1:

        def rule_total_mass_balance(b):
            return b.flow_mol_phase[b.params.phase_list[1]] == b.flow_mol

        b.total_flow_balance = Constraint(rule=rule_total_mass_balance)

        def rule_comp_mass_balance(b, i):
            return b.mole_frac_comp[i]*1e3 == \
                1e3*b.mole_frac_phase_comp[b.params.phase_list[1], i]

        b.component_flow_balances = Constraint(b.params.component_list,
                                               rule=rule_comp_mass_balance)

        def rule_phase_frac(b, p):
            return b.phase_frac[p] == 1

        b.phase_fraction_constraint = Constraint(b.params.phase_list,
                                                 rule=rule_phase_frac)

    elif len(b.params.phase_list) == 2:
        # For two phase, use Rachford-Rice formulation
        def rule_total_mass_balance(b):
            return sum(b.flow_mol_phase[p] for p in b.params.phase_list) == \
                b.flow_mol

        b.total_flow_balance = Constraint(rule=rule_total_mass_balance)

        def rule_comp_mass_balance(b, i):
            return b.flow_mol_comp[i] == sum(
                b.flow_mol_phase[p] * b.mole_frac_phase_comp[p, i]
                for p in b.params.phase_list
                if (p, i) in b.params._phase_component_set)

        b.component_flow_balances = Constraint(b.params.component_list,
                                               rule=rule_comp_mass_balance)

        def rule_mole_frac(b):
            return 1e3*sum(b.mole_frac_phase_comp[b.params.phase_list[1], i]
                           for i in b.params.component_list
                           if (b.params.phase_list[1], i)
                           in b.params._phase_component_set) -\
                1e3*sum(b.mole_frac_phase_comp[b.params.phase_list[2], i]
                        for i in b.params.component_list
                        if (b.params.phase_list[2], i)
                        in b.params._phase_component_set) == 0

        b.sum_mole_frac = Constraint(rule=rule_mole_frac)

        def rule_phase_frac(b, p):
            return b.phase_frac[p] * b.flow_mol == b.flow_mol_phase[p]

        b.phase_fraction_constraint = Constraint(b.params.phase_list,
                                                 rule=rule_phase_frac)

    else:
        # Otherwise use a general formulation
        def rule_comp_mass_balance(b, i):
            return b.flow_mol_comp[i] == sum(
                b.flow_mol_phase[p] * b.mole_frac_phase_comp[p, i]
                for p in b.params.phase_list
                if (p, i) in b.params._phase_component_set)

        b.component_flow_balances = Constraint(b.params.component_list,
                                               rule=rule_comp_mass_balance)

        def rule_mole_frac(b, p):
            return 1e3 * sum(b.mole_frac_phase_comp[p, i]
                             for i in b.params.component_list
                             if (p, i) in b.params._phase_component_set) == 1e3

        b.sum_mole_frac = Constraint(b.params.phase_list, rule=rule_mole_frac)

        def rule_phase_frac(b, p):
            return b.phase_frac[p] * b.flow_mol == b.flow_mol_phase[p]

        b.phase_fraction_constraint = Constraint(b.params.phase_list,
                                                 rule=rule_phase_frac)

    # -------------------------------------------------------------------------
    # General Methods
    def get_material_flow_terms_FTPx(p, j):
        """Create material flow terms for control volume."""
        if j in b.params.component_list:
            return b.flow_mol_phase[p] * b.mole_frac_phase_comp[p, j]
        else:
            return 0

    b.get_material_flow_terms = get_material_flow_terms_FTPx

    def get_enthalpy_flow_terms_FTPx(p):
        """Create enthalpy flow terms."""
        return b.flow_mol_phase[p] * b.enth_mol_phase[p]

    b.get_enthalpy_flow_terms = get_enthalpy_flow_terms_FTPx

    def get_material_density_terms_FTPx(p, j):
        """Create material density terms."""
        if j in b.params.component_list:
            return b.dens_mol_phase[p] * b.mole_frac_phase_comp[p, j]
        else:
            return 0

    b.get_material_density_terms = get_material_density_terms_FTPx

    def get_energy_density_terms_FTPx(p):
        """Create energy density terms."""
        return b.dens_mol_phase[p] * b.enth_mol_phase[p]

    b.get_energy_density_terms = get_energy_density_terms_FTPx

    def default_material_balance_type_FTPx():
        return MaterialBalanceType.componentTotal

    b.default_material_balance_type = default_material_balance_type_FTPx

    def default_energy_balance_type_FTPx():
        return EnergyBalanceType.enthalpyTotal

    b.default_energy_balance_type = default_energy_balance_type_FTPx

    def get_material_flow_basis_FTPx():
        return MaterialFlowBasis.molar

    b.get_material_flow_basis = get_material_flow_basis_FTPx

    def define_state_vars_FTPx():
        """Define state vars."""
        return {
            "flow_mol_comp": b.flow_mol_comp,
            "temperature": b.temperature,
            "pressure": b.pressure
        }

    b.define_state_vars = define_state_vars_FTPx

    def define_display_vars_FTPx():
        """Define display vars."""
        return {
            "Molar Flowrate": b.flow_mol_comp,
            "Temperature": b.temperature,
            "Pressure": b.pressure
        }

    b.define_display_vars = define_display_vars_FTPx
Exemple #18
0
#
# Author:  Gabe Hackebeil
# Purpose: For regression testing to ensure that the Pyomo
#          NL writer properly reclassifies nonlinear expressions
#          as linear or trivial when fixing variables or params
#          cause such a situation.
#
#          This test model relies on the gjh_asl_json executable. It
#          will not solve if sent to a real optimizer.
#

from pyomo.environ import ConcreteModel, Var, Param, Objective, Constraint, simple_constraint_rule

model = ConcreteModel()

model.x = Var()
model.y = Var()
model.z = Var()
model.q = Param(initialize=0.0)
model.p = Param(initialize=0.0, mutable=True)

model.obj = Objective( expr=model.x*model.y +\
                            model.z*model.y +\
                            model.q*model.y +\
                            model.y*model.y*model.q +\
                            model.p*model.y +\
                            model.y*model.y*model.p +\
                            model.y*model.y*model.z +\
                            model.z*(model.y**2))

model.con1 = Constraint(expr=model.x * model.y == 0)
Exemple #19
0
    def test_findComponentOn_nestedTuples(self):
        # Tests for #1069
        m = ConcreteModel()
        m.x = Var()
        m.c = Constraint(Any)
        m.c[0] = m.x >= 0
        m.c[(1, )] = m.x >= 1
        m.c[(2, )] = m.x >= 2
        m.c[2] = m.x >= 3
        self.assertIs(ComponentUID(m.c[0]).find_component_on(m), m.c[0])
        self.assertIs(ComponentUID('c[0]').find_component_on(m), m.c[0])
        self.assertIsNone(ComponentUID('c[(0,)]').find_component_on(m))
        self.assertIs(
            ComponentUID(m.c[(1, )]).find_component_on(m), m.c[(1, )])
        self.assertIs(ComponentUID('c[(1,)]').find_component_on(m), m.c[(1, )])
        self.assertIsNone(ComponentUID('c[1]').find_component_on(m))
        self.assertIs(ComponentUID('c[(2,)]').find_component_on(m), m.c[(2, )])
        self.assertIs(ComponentUID('c[2]').find_component_on(m), m.c[2])
        self.assertEqual(len(m.c), 4)

        self.assertEqual(repr(ComponentUID(m.c[0])), "c[0]")
        self.assertEqual(repr(ComponentUID(m.c[(1, )])), "c[(1,)]")
        self.assertEqual(str(ComponentUID(m.c[0])), "c[0]")
        self.assertEqual(str(ComponentUID(m.c[(1, )])), "c[(1,)]")

        m = ConcreteModel()
        m.x = Var()
        m.c = Constraint([0, 1])
        m.c[0] = m.x >= 0
        m.c[(1, )] = m.x >= 1
        self.assertIs(ComponentUID(m.c[0]).find_component_on(m), m.c[0])
        self.assertIs(ComponentUID(m.c[(0, )]).find_component_on(m), m.c[0])
        self.assertIs(ComponentUID('c[0]').find_component_on(m), m.c[0])
        self.assertIs(ComponentUID('c[(0,)]').find_component_on(m), m.c[0])
        self.assertIs(ComponentUID(m.c[1]).find_component_on(m), m.c[1])
        self.assertIs(ComponentUID(m.c[(1, )]).find_component_on(m), m.c[1])
        self.assertIs(ComponentUID('c[(1,)]').find_component_on(m), m.c[1])
        self.assertIs(ComponentUID('c[1]').find_component_on(m), m.c[1])
        self.assertEqual(len(m.c), 2)

        m = ConcreteModel()
        m.b = Block(Any)
        m.b[0].c = Block(Any)
        m.b[0].c[0].x = Var()
        m.b[(1, )].c = Block(Any)
        m.b[(1, )].c[(1, )].x = Var()
        ref = m.b[0].c[0].x
        self.assertIs(ComponentUID(ref).find_component_on(m), ref)
        ref = 'm.b[0].c[(0,)].x'
        self.assertIsNone(ComponentUID(ref).find_component_on(m))
        ref = m.b[(1, )].c[(1, )].x
        self.assertIs(ComponentUID(ref).find_component_on(m), ref)
        ref = 'm.b[(1,)].c[1].x'
        self.assertIsNone(ComponentUID(ref).find_component_on(m))

        buf = {}
        ref = m.b[0].c[0].x
        self.assertIs(
            ComponentUID(ref, cuid_buffer=buf).find_component_on(m), ref)
        self.assertEqual(len(buf), 3)
        ref = 'm.b[0].c[(0,)].x'
        self.assertIsNone(
            ComponentUID(ref, cuid_buffer=buf).find_component_on(m))
        self.assertEqual(len(buf), 3)
        ref = m.b[(1, )].c[(1, )].x
        self.assertIs(
            ComponentUID(ref, cuid_buffer=buf).find_component_on(m), ref)
        self.assertEqual(len(buf), 4)
        ref = 'm.b[(1,)].c[1].x'
        self.assertIsNone(
            ComponentUID(ref, cuid_buffer=buf).find_component_on(m))
        self.assertEqual(len(buf), 4)
Exemple #20
0
#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright 2017 National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

from pyomo.environ import Var


class Foo:
    pass


anotherObject = Foo()
anotherObject.x = Var([10])
anotherObject.x.value = 42
Exemple #21
0
 def b2(b2, i, j):
     b2.v = Var()
     b2.v1 = Var(m.d1_3)
     b2.v2 = Var(m.d1_1, m.d1_2)
     b2.vn = Var(m.d1_1, m.dn, m.d1_2)
    def test_xfrm_special_atoms_nonroot(self):
        m = ConcreteModel()
        m.s = RangeSet(3)
        m.Y = BooleanVar(m.s)
        m.p = LogicalConstraint(
            expr=m.Y[1].implies(atleast(2, m.Y[1], m.Y[2], m.Y[3])))
        TransformationFactory('core.logical_to_linear').apply_to(m)
        Y_aug = m.logic_to_linear.augmented_vars
        self.assertEqual(len(Y_aug), 1)
        self.assertEqual(Y_aug[1].domain, BooleanSet)
        _constrs_contained_within(
            self, [
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (1 + 2 * Y_aug[1].get_associated_binary()), 0),
                (1, (1 - m.Y[1].get_associated_binary()) + \
                 Y_aug[1].get_associated_binary(), None),
                (None, 2 - 2 * (1 - Y_aug[1].get_associated_binary()) - \
                 sum(m.Y[:].get_associated_binary()), 0)
            ], m.logic_to_linear.transformed_constraints)

        m = ConcreteModel()
        m.s = RangeSet(3)
        m.Y = BooleanVar(m.s)
        m.p = LogicalConstraint(
            expr=m.Y[1].implies(atmost(2, m.Y[1], m.Y[2], m.Y[3])))
        TransformationFactory('core.logical_to_linear').apply_to(m)
        Y_aug = m.logic_to_linear.augmented_vars
        self.assertEqual(len(Y_aug), 1)
        self.assertEqual(Y_aug[1].domain, BooleanSet)
        _constrs_contained_within(
            self, [
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (1 - Y_aug[1].get_associated_binary() + 2), 0),
                (1, (1 - m.Y[1].get_associated_binary()) + \
                 Y_aug[1].get_associated_binary(), None),
                (None, 3 - 3 * Y_aug[1].get_associated_binary() - \
                 sum(m.Y[:].get_associated_binary()), 0)
            ], m.logic_to_linear.transformed_constraints)

        m = ConcreteModel()
        m.s = RangeSet(3)
        m.Y = BooleanVar(m.s)
        m.p = LogicalConstraint(
            expr=m.Y[1].implies(exactly(2, m.Y[1], m.Y[2], m.Y[3])))
        TransformationFactory('core.logical_to_linear').apply_to(m)
        Y_aug = m.logic_to_linear.augmented_vars
        self.assertEqual(len(Y_aug), 3)
        self.assertEqual(Y_aug[1].domain, BooleanSet)
        _constrs_contained_within(
            self, [
                (1, (1 - m.Y[1].get_associated_binary()) + \
                 Y_aug[1].get_associated_binary(), None),
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (1 - Y_aug[1].get_associated_binary() + 2), 0),
                (None, 2 - 2 * (1 - Y_aug[1].get_associated_binary()) - \
                 sum(m.Y[:].get_associated_binary()), 0),
                (1, sum(Y_aug[:].get_associated_binary()), None),
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (1 + 2 * (1 - Y_aug[2].get_associated_binary())), 0),
                (None, 3 - 3 * (1 - Y_aug[3].get_associated_binary()) - \
                 sum(m.Y[:].get_associated_binary()), 0),
            ], m.logic_to_linear.transformed_constraints)

        # Note: x is now a variable
        m = ConcreteModel()
        m.s = RangeSet(3)
        m.Y = BooleanVar(m.s)
        m.x = Var(bounds=(1, 3))
        m.p = LogicalConstraint(
            expr=m.Y[1].implies(exactly(m.x, m.Y[1], m.Y[2], m.Y[3])))
        TransformationFactory('core.logical_to_linear').apply_to(m)
        Y_aug = m.logic_to_linear.augmented_vars
        self.assertEqual(len(Y_aug), 3)
        self.assertEqual(Y_aug[1].domain, BooleanSet)
        _constrs_contained_within(
            self, [
                (1, (1 - m.Y[1].get_associated_binary()) + \
                 Y_aug[1].get_associated_binary(), None),
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (m.x + 2 * (1 - Y_aug[1].get_associated_binary())), 0),
                (None, m.x - 3 * (1 - Y_aug[1].get_associated_binary()) - \
                 sum(m.Y[:].get_associated_binary()), 0),
                (1, sum(Y_aug[:].get_associated_binary()), None),
                (None, sum(m.Y[:].get_associated_binary()) - \
                 (m.x - 1 + 3 * (1 - Y_aug[2].get_associated_binary())), 0),
                (None, m.x + 1 - 4 * (1 - Y_aug[3].get_associated_binary()) - \
                 sum(m.Y[:].get_associated_binary()), 0),
            ], m.logic_to_linear.transformed_constraints)
    def _make_performance(self):
        """
        Define constraints which describe the behaviour of the unit model.

        Args:
            None

        Returns:
            None
        """
        # Set references to balance terms at unit level
        self.heat_duty_side_1 = Reference(self.side_1.heat)
        self.heat_duty_side_2 = Reference(self.side_2.heat)
        self.heat_duty_side_3 = Reference(self.side_3.heat)

        if self.config.has_pressure_change is True:
            self.deltaP_side_1 = Reference(self.side_1.deltaP)
            self.deltaP_side_2 = Reference(self.side_2.deltaP)
            self.deltaP_side_3 = Reference(self.side_3.deltaP)

        # Performance parameters and variables
        # Temperature driving force
        self.temperature_driving_force_side_2 = Var(self.flowsheet().config.
                                                    time,
                                                    initialize=1.0,
                                                    doc='Mean driving force '
                                                    'for heat exchange')

        # Temperature driving force
        self.temperature_driving_force_side_3 = Var(self.flowsheet().
                                                    config.time,
                                                    initialize=1.0,
                                                    doc='Mean driving force '
                                                    'for heat exchange')

        # Temperature difference at side 2 inlet
        self.side_2_inlet_dT = Var(self.flowsheet().config.time,
                                   initialize=1.0,
                                   doc='Temperature difference '
                                   'at side 2 inlet')

        # Temperature difference at side 2 outlet
        self.side_2_outlet_dT = Var(self.flowsheet().config.time,
                                    initialize=1.0,
                                    doc='Temperature difference '
                                    'at side 2 outlet')

        # Temperature difference at side 3 inlet
        self.side_3_inlet_dT = Var(self.flowsheet().config.time,
                                   initialize=1.0,
                                   doc='Temperature difference'
                                   ' at side 3 inlet')

        # Temperature difference at side 3 outlet
        self.side_3_outlet_dT = Var(self.flowsheet().config.time,
                                    initialize=1.0,
                                    doc='Temperature difference '
                                    'at side 3 outlet')

        # Driving force side 2 (Underwood approximation)
        @self.Constraint(self.flowsheet().config.time,
                         doc="Log mean temperature difference calculation "
                         "using Underwood approximation")
        def LMTD_side_2(b, t):
            return b.temperature_driving_force_side_2[t] == \
                ((b.side_2_inlet_dT[t]**(1/3)
                  + b.side_2_outlet_dT[t]**(1/3))/2)**(3)

        # Driving force side 3 (Underwood approximation)
        @self.Constraint(self.flowsheet().config.time,
                         doc="Log mean temperature difference calculation "
                         "using Underwood approximation")
        def LMTD_side_3(b, t):
            return b.temperature_driving_force_side_3[t] == \
                ((b.side_3_inlet_dT[t]**(1/3)
                  + b.side_3_outlet_dT[t]**(1/3))/2)**(3)

        # Heat duty side 2
        @self.Constraint(self.flowsheet().config.time,
                         doc="Heat transfer rate")
        def heat_duty_side_2_eqn(b, t):
            return b.heat_duty_side_2[t] == \
                (b.ua_side_2[t] * b.temperature_driving_force_side_2[t])

        # Heat duty side 3
        @self.Constraint(self.flowsheet().config.time,
                         doc="Heat transfer rate")
        def heat_duty_side_3_eqn(b, t):
            return b.heat_duty_side_3[t] == \
                (b.ua_side_3[t]*b.temperature_driving_force_side_3[t])

        # Energy balance equation
        @self.Constraint(self.flowsheet().config.time,
                         doc="Energy balance between two sides")
        def heat_duty_side_1_eqn(b, t):
            return -b.heat_duty_side_1[t]*(1-b.frac_heatloss) == \
                (b.heat_duty_side_2[t] + b.heat_duty_side_3[t])
Exemple #24
0
    def _make_performance(self):
        """
        Define constraints which describe the behaviour of the unit model.
        """

        # thermal conductivity of drum
        self.cond_therm_metal = Param(initialize=40, mutable=True)

        # thermal conductivity of insulation
        self.cond_therm_insulation = Param(initialize=0.08, mutable=True)

        # thermal conductivity of air
        self.cond_therm_air = Param(initialize=0.03, mutable=True)

        # thermal diffusivity of drum
        #self.diff_therm_metal = Param(initialize = 9.5E-6, mutable=True)

        # material density of drum
        self.density_thermal_metal = Param(initialize=7753, mutable=True)

        # heat capacity of drum
        self.heat_capacity_thermal_drum = Param(initialize=486, mutable=True)

        # Young modulus
        self.Young_modulus = Param(initialize=2.07E5, mutable=True)

        # Poisson's ratio
        self.Poisson_ratio = Param(initialize=0.292, mutable=True)

        # Coefficient of thermal expansion
        self.coefficient_therm_expansion = Param(initialize=1.4E-5,
                                                 mutable=True)

        # constant related to Ra, (gravity*expansion_coefficient*density/viscosity/thermal_diffusivity)^(1/6)
        # use properties at 50 C and 1 atm, 6.84e7^(1/6)=20.223
        self.const_Ra_root6 = Param(initialize=20.223, mutable=True)

        # constant related to Nu for free convection, 0.387/(1+0.721*Pr^(-9/16))^(8/27)
        # use properties at 50 C and 1 atm
        self.const_Nu = Param(initialize=0.322, mutable=True)

        # ambient pressure
        self.pres_amb = Param(initialize=0.81E5, doc="ambient pressure")

        # ambient temperature
        self.temp_amb = Var(self.flowsheet().config.time,
                            initialize=300,
                            doc="ambient temperature")

        # inside heat transfer coefficient
        self.h_in = Var(self.flowsheet().config.time,
                        initialize=1,
                        doc="inside heat transfer coefficient")

        # outside heat transfer coefficient
        self.h_out = Var(self.flowsheet().config.time,
                         initialize=1,
                         doc="outside heat transfer coefficient")

        # insulation free convection heat transfer coefficient
        self.h_free_conv = Var(
            self.flowsheet().config.time,
            initialize=1,
            doc="insulation free convection heat transfer coefficient")

        # Ra number of free convection
        self.N_Ra_root6 = Var(
            self.flowsheet().config.time,
            initialize=80,
            doc="1/6 power of Ra number of free convection of air")

        # Nu number  of free convection
        self.N_Nu = Var(self.flowsheet().config.time,
                        initialize=1,
                        doc="Nu number of free convection of air")

        # Define the continuous domains for model
        self.r = ContinuousSet(bounds=(self.rin_drum, self.rout_drum))

        # Temperature across wall thickness
        self.T = Var(self.flowsheet().config.time,
                     self.r,
                     bounds=(280, 800),
                     initialize=550)

        # Declare derivatives in the model
        if self.config.dynamic is True:
            self.dTdt = DerivativeVar(self.T, wrt=self.flowsheet().config.time)
        self.dTdr = DerivativeVar(self.T, wrt=self.r)
        self.d2Tdr2 = DerivativeVar(self.T, wrt=(self.r, self.r))

        discretizer = TransformationFactory('dae.finite_difference')
        discretizer.apply_to(self,
                             nfe=self.config.finite_elements,
                             wrt=self.r,
                             scheme='CENTRAL')

        # Add performance variables
        self.level = Var(self.flowsheet().config.time,
                         initialize=1.0,
                         doc='Water level from the bottom of the drum')

        # Velocity of fluid inside downcomer pipe
        self.velocity_downcomer = Var(
            self.flowsheet().config.time,
            initialize=10.0,
            doc='Liquid water velocity at the top of downcomer')

        # Pressure change due to contraction
        self.deltaP_contraction = Var(self.flowsheet().config.time,
                                      initialize=-1.0,
                                      doc='Pressure change due to contraction')

        # Pressure change due to gravity
        self.deltaP_gravity = Var(self.flowsheet().config.time,
                                  initialize=1.0,
                                  doc='Pressure change due to gravity')

        # thermal diffusivity of drum
        @self.Expression(doc="Thermal diffusivity of drum")
        def diff_therm_metal(b):
            return b.cond_therm_metal / (b.density_thermal_metal *
                                         b.heat_capacity_thermal_drum)

        # Expressure for the angle from the drum center to the circumference point at water level
        @self.Expression(self.flowsheet().config.time,
                         doc="angle of water level")
        def alpha_drum(b, t):
            return asin((b.level[t] - b.rin_drum) / b.rin_drum)

        # Expressure for the fraction of wet area
        @self.Expression(self.flowsheet().config.time,
                         doc="fraction of wet area")
        def frac_wet_area(b, t):
            return (b.alpha_drum[t] + b.pi / 2) / b.pi

        # Constraint for volume liquid in drum
        @self.Constraint(self.flowsheet().config.time,
                         doc="volume of liquid in drum")
        def volume_eqn(b, t):
            return b.volume[t] == \
                   ((b.alpha_drum[t]+0.5*b.pi)*b.rin_drum**2 + \
                   b.rin_drum*cos(b.alpha_drum[t])*(b.level[t]-b.rin_drum))* \
                   b.length_drum

        # Equation for velocity at the entrance of downcomer
        @self.Constraint(self.flowsheet().config.time,
                         doc="Vecolity at entrance of downcomer")
        def velocity_eqn(b, t):
            return b.velocity_downcomer[t]*0.25*b.pi*b.diameter_downcomer**2*b.count_downcomer \
                   == b.control_volume.properties_out[t].flow_vol

        # Pressure change equation for contraction, -0.5*1/2*density*velocity^2 for stagnation head loss
        # plus 1/2*density*velocity^2 dynamic head (acceleration pressure change)
        @self.Constraint(self.flowsheet().config.time,
                         doc="pressure change due to contraction")
        def pressure_change_contraction_eqn(b, t):
            return b.deltaP_contraction[t] == \
                   -0.75 * b.control_volume.properties_out[t].dens_mass_phase["Liq"] * \
                   b.velocity_downcomer[t]**2

        # Pressure change equation for gravity, density*gravity*height
        @self.Constraint(self.flowsheet().config.time,
                         doc="pressure change due to gravity")
        def pressure_change_gravity_eqn(b, t):
            return b.deltaP_gravity[t] == \
                   b.control_volume.properties_out[t].dens_mass_phase["Liq"] * b.gravity * b.level[t]

        # Total pressure change equation
        @self.Constraint(self.flowsheet().config.time, doc="pressure drop")
        def pressure_change_total_eqn(b, t):
            return b.deltaP[t] == b.deltaP_contraction[t] + b.deltaP_gravity[t]

        # Constraint for heat conduction equation
        @self.Constraint(self.flowsheet().config.time,
                         self.r,
                         doc="1-D heat conduction equation through radius")
        def heat_conduction_eqn(b, t, r):
            if r == b.r.first() or r == b.r.last():
                return Constraint.Skip
            if self.config.dynamic is True:
                return b.dTdt[t, r] == b.diff_therm_metal * b.d2Tdr2[
                    t, r] + b.diff_therm_metal * (1 / r) * b.dTdr[t, r]
            else:
                return 0 == b.diff_therm_metal * b.d2Tdr2[
                    t, r] + b.diff_therm_metal * (1 / r) * b.dTdr[t, r]

        @self.Constraint(self.flowsheet().config.time, doc="inner wall BC")
        def inner_wall_bc_eqn(b, t):
            return b.h_in[t]*(b.control_volume.properties_out[t].temperature - b.T[t,b.r.first()]) == \
                   -b.dTdr[t,b.r.first()]*b.cond_therm_metal

        @self.Constraint(self.flowsheet().config.time, doc="outer wall BC")
        def outer_wall_bc_eqn(b, t):
            return b.h_out[t]*(b.T[t,b.r.last()] - b.temp_amb[t]) == \
                   -b.dTdr[t, b.r.last()]*b.cond_therm_metal

        # Inner wall BC for dTdt
        @self.Constraint(self.flowsheet().config.time,
                         doc="extra inner wall temperature derivative")
        def extra_at_inner_wall_eqn(b, t):
            if self.config.dynamic is True:
                term = b.dTdt[t, b.r.first()]
            else:
                term = 0
            return term == 4*b.diff_therm_metal*(b.r.first()+b.r[2])/ \
                (b.r[2]-b.r.first())**2/(3*b.r.first()+b.r[2])*(b.T[t,b.r[2]] \
                -b.T[t,b.r.first()]) + 8*b.diff_therm_metal/b.cond_therm_metal*b.h_in[t]*b.r.first()/ \
                (b.r[2]-b.r.first())/(3*b.r.first()+b.r[2])*(b.control_volume.properties_out[t].temperature \
                -b.T[t,b.r.first()])

        @self.Constraint(self.flowsheet().config.time,
                         doc="extra outer wall temperature derivative")
        def extra_at_outer_wall_eqn(b, t):
            if self.config.dynamic is True:
                term = b.dTdt[t, b.r.last()]
            else:
                term = 0
            return term == 4*b.diff_therm_metal*(b.r.last()+b.r[-2])/ \
                (b.r.last()-b.r[-2])**2/(3*b.r.last()+b.r[-2])*(b.T[t,b.r[-2]] \
                -b.T[t,b.r.last()]) + 8*b.diff_therm_metal/b.cond_therm_metal*b.h_out[t]*b.r.last()/ \
                (b.r.last()-b.r[-2])/(3*b.r.last()+b.r[-2])*(b.temp_amb[t] \
                -b.T[t,b.r.last()])

        # reduced pressure expression
        @self.Expression(self.flowsheet().config.time, doc="reduced pressure")
        def pres_reduced(b, t):
            return b.control_volume.properties_out[t].pressure / 2.2048e7

        # calculate inner side heat transfer coefficient with minimum temperature difference set to sqrt(0.1)
        # multipling wet area fraction to convert it to the value based on total circumference
        @self.Constraint(self.flowsheet().config.time,
                         doc="inner side heat transfer coefficient")
        def h_in_eqn(b, t):
            return b.h_in[t] == 2178.6*(b.control_volume.properties_out[t].pressure/2.2048e7)**0.36\
                   /(-log10(b.control_volume.properties_out[t].pressure/2.2048e7))**1.65 *\
                   (0.1+(b.control_volume.properties_out[t].temperature-b.T[t,b.r.first()])**2)*b.frac_wet_area[t]

        # Expressure for insulation heat transfer (conduction) resistance based on drum metal outside diameter
        @self.Expression(doc="heat transfer resistance of insulation layer")
        def resistance_insulation(b):
            return b.rout_drum * log((b.rout_drum + b.thickness_insulation) /
                                     b.rout_drum) / b.cond_therm_insulation

        # h_out equation considering conduction through insulation and free convection between insulation and ambient
        @self.Constraint(self.flowsheet().config.time,
                         doc="outer side heat transfer coefficient")
        def h_out_eqn(b, t):
            return b.h_out[t] * (b.resistance_insulation +
                                 1 / b.h_free_conv[t]) == 1.0

        # Expressure for outside insulation wall temperature (skin temperature)
        @self.Expression(self.flowsheet().config.time,
                         doc="outside insulation wall temperature")
        def temp_insulation_outside(b, t):
            return b.temp_amb[t] + (b.T[t, b.r.last()] - b.temp_amb[t]
                                    ) * b.h_out[t] / b.h_free_conv[t]

        # Ra number equation
        @self.Constraint(self.flowsheet().config.time,
                         doc="Ra number of free convection")
        def Ra_number_eqn(b, t):
            return b.N_Ra_root6[t] == b.const_Ra_root6 * sqrt(
                b.dout_drum + 2 * b.thickness_insulation) * (
                    b.T[t, b.r.last()] - b.temp_amb[t])**0.166667

        # Nu number equation
        @self.Constraint(self.flowsheet().config.time,
                         doc=" Nu number of free convection")
        def Nu_number_eqn(b, t):
            return b.N_Nu[t] == (0.6 + b.const_Nu * b.N_Ra_root6[t])**2

        # free convection coefficient based on the drum metal outside diameter
        @self.Constraint(
            self.flowsheet().config.time,
            doc=
            "free convection heat transfer coefficient between insulation wall and ambient"
        )
        def h_free_conv_eqn(b, t):
            return b.h_free_conv[
                t] == b.N_Nu[t] * b.cond_therm_air / b.dout_drum

        @self.Constraint(self.flowsheet().config.time,
                         doc="heat loss of water")
        def heat_loss_eqn(b, t):
            return b.heat_duty[t] == b.area_drum*b.h_in[t]*(b.T[t,b.r.first()]\
                   -b.control_volume.properties_out[t].temperature)

        ### Calculate mechanical and thermal stresses
        # ----------------------------------------------------------------------------------------------

        # Integer indexing for radius domain
        self.rindex = Param(self.r,
                            initialize=1,
                            mutable=True,
                            doc="inter indexing for radius domain")

        # calculate integral point for mean temperature in the wall
        @self.Expression(self.flowsheet().config.time,
                         doc="integral point used to estimate mean temperature"
                         )
        def int_mean_temp(b, t):
            return 2*(b.r[2]-b.r[1])/(b.rout_drum**2-b.rin_drum**2)*(sum(0.5*(b.r[i-1]*b.T[t,b.r[i-1]]+\
                b.r[i]*b.T[t,b.r[i]]) for i in range(2,len(b.r)+1)))

        for index_r, value_r in enumerate(self.r, 1):
            self.rindex[value_r] = index_r

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="integral point at each element")
        def int_temp(b, t, r):
            if b.rindex[r].value == 1:
                return b.T[t, b.r.first()]
            else:
                return 2*(b.r[2]-b.r[1])/(b.r[b.rindex[r].value]**2-b.rin_drum**2)\
                *(sum(0.5*(b.r[j-1]*b.T[t,b.r[j-1]]+b.r[j]*b.T[t,b.r[j]])\
                 for j in range(2,b.rindex[r].value+1)))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at radial direction")
        def therm_stress_radial(b, t, r):
            return 0.5*b.Young_modulus*b.coefficient_therm_expansion/(1-b.Poisson_ratio)\
            *((1-b.rin_drum**2/r**2)*(b.int_mean_temp[t]-b.int_temp[t,r]))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at circumferential direction")
        def therm_stress_circumferential(b, t, r):
            return 0.5*b.Young_modulus*b.coefficient_therm_expansion/(1-b.Poisson_ratio)\
                *((1+b.rin_drum**2/r**2)*b.int_mean_temp[t]+(1-b.rin_drum**2/r**2)*b.int_temp[t,r]-2*b.T[t,r])

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at axial direction")
        def therm_stress_axial(b, t, r):
            return b.Young_modulus * b.coefficient_therm_expansion / (
                1 - b.Poisson_ratio) * (b.int_mean_temp[t] - b.T[t, r])

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at radial direction")
        def mech_stress_radial(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2)+(1E-5*(b.pres_amb-b.control_volume.properties_out[t].pressure)\
                *b.rin_drum**2*b.rout_drum**2/(r**2*(b.rout_drum**2-b.rin_drum**2))))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at circumferential direction")
        def mech_stress_circumferential(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2)-(1E-5*(b.pres_amb-b.control_volume.properties_out[t].pressure)\
                    *b.rin_drum**2*b.rout_drum**2/(r**2*(b.rout_drum**2-b.rin_drum**2))))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at axial direction")
        def mech_stress_axial(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2))
Exemple #25
0
class SteamValveData(PressureChangerData):
    # Same settings as the default pressure changer, but force to expander with
    # isentropic efficiency
    CONFIG = PressureChangerData.CONFIG()
    _define_config(CONFIG)

    def build(self):
        super().build()

        self.valve_opening = Var(self.flowsheet().config.time,
                                 initialize=1,
                                 doc="Fraction open for valve from 0 to 1")
        self.Cv = Var(initialize=0.1,
                      doc="Valve flow coefficent, for vapor "
                      "[mol/s/Pa] for liquid [mol/s/Pa^0.5]")
        self.flow_scale = Param(
            mutable=True,
            default=1e3,
            doc=
            "Scaling factor for pressure flow relation should be approximatly"
            " the same order of magnitude as the expected flow.")
        self.Cv.fix()
        self.valve_opening.fix()

        # set up the valve function rule.  I'm not sure these matter too much
        # for us, but the options are easy enough to provide.
        if self.config.valve_function == ValveFunctionType.linear:
            rule = _linear_rule
        elif self.config.valve_function == ValveFunctionType.quick_opening:
            rule = _quick_open_rule
        elif self.config.valve_function == ValveFunctionType.equal_percentage:
            self.alpha = Var(initialize=1, doc="Valve function parameter")
            self.alpha.fix()
            rule = equal_percentage_rule
        else:
            rule = self.config.valve_function_rule

        self.valve_function = Expression(self.flowsheet().config.time,
                                         rule=rule,
                                         doc="Valve function expression")

        if self.config.phase == "Liq":
            rule = _liquid_pressure_flow_rule
        else:
            rule = _vapor_pressure_flow_rule

        self.pressure_flow_equation = Constraint(self.flowsheet().config.time,
                                                 rule=rule)

    def initialize(self,
                   state_args={},
                   outlvl=0,
                   solver='ipopt',
                   optarg={
                       'tol': 1e-6,
                       'max_iter': 30
                   }):
        """
        Initialize the turbine stage model.  This deactivates the
        specialized constraints, then does the isentropic turbine initialization,
        then reactivates the constraints and solves.

        Args:
            state_args (dict): Initial state for property initialization
            outlvl (int): Amount of output (0 to 3) 0 is lowest
            solver (str): Solver to use for initialization
            optarg (dict): Solver arguments dictionary
        """
        stee = True if outlvl >= 3 else False
        # sp is what to save to make sure state after init is same as the start
        #   saves value, fixed, and active state, doesn't load originally free
        #   values, this makes sure original problem spec is same but initializes
        #   the values of free vars
        sp = StoreSpec.value_isfixed_isactive(only_fixed=True)
        istate = to_json(self, return_dict=True, wts=sp)

        self.deltaP[:].unfix()
        self.ratioP[:].unfix()

        # fix inlet and free outlet
        for t in self.flowsheet().config.time:
            for k, v in self.inlet.vars.items():
                v[t].fix()
            for k, v in self.outlet.vars.items():
                v[t].unfix()
            # to calculate outlet pressure
            Pout = self.outlet.pressure[t]
            Pin = self.inlet.pressure[t]
            if self.deltaP[t].value is not None:
                prdp = value((self.deltaP[t] - Pin) / Pin)
            else:
                prdp = -100  # crazy number to say don't use deltaP as guess
            if value(Pout / Pin) > 1 or value(Pout / Pin) < 0.0:
                if value(self.ratioP[t]) <= 1 and value(self.ratioP[t]) >= 0:
                    Pout.value = value(Pin * self.ratioP[t])
                elif prdp <= 1 and prdp >= 0:
                    Pout.value = value(prdp * Pin)
                else:
                    Pout.value = value(Pin * 0.95)
            self.deltaP[t] = value(Pout - Pin)
            self.ratioP[t] = value(Pout / Pin)

        # Make sure the initialization problem has no degrees of freedom
        # This shouldn't happen here unless there is a bug in this
        dof = degrees_of_freedom(self)
        try:
            assert (dof == 0)
        except:
            _log.exception("degrees_of_freedom = {}".format(dof))
            raise

        # one bad thing about reusing this is that the log messages aren't
        # really compatible with being nested inside another initialization
        super().initialize(state_args=state_args,
                           outlvl=outlvl,
                           solver=solver,
                           optarg=optarg)

        # reload original spec
        from_json(self, sd=istate, wts=sp)

    def _get_performance_contents(self, time_point=0):
        pc = super()._get_performance_contents(time_point=time_point)

        pc["vars"]["Opening"] = self.valve_opening[time_point]
        pc["vars"]["Valve Coefficient"] = self.Cv
        if self.config.valve_function == ValveFunctionType.equal_percentage:
            pc["vars"]["alpha"] = self.alpha

        pc["params"] = {}
        pc["params"]["Flow Scaling"] = self.flow_scale

        return pc
Exemple #26
0
class Drum1DData(UnitModelBlockData):
    """
    1-D Boiler Drum Unit Operation Class
    """
    CONFIG = ConfigBlock()
    CONFIG.declare(
        "dynamic",
        ConfigValue(domain=In([useDefault, True, False]),
                    default=useDefault,
                    description="Dynamic model flag",
                    doc="""Indicates whether this model will be dynamic or not,
**default** = useDefault.
**Valid values:** {
**useDefault** - get flag from parent (default = False),
**True** - set as a dynamic model,
**False** - set as a steady-state model.}"""))
    CONFIG.declare(
        "has_holdup",
        ConfigValue(
            default=False,
            domain=In([True, False]),
            description="Holdup construction flag",
            doc="""Indicates whether holdup terms should be constructed or not.
Must be True if dynamic = True,
**default** - False.
**Valid values:** {
**True** - construct holdup terms,
**False** - do not construct holdup terms}"""))
    CONFIG.declare(
        "material_balance_type",
        ConfigValue(
            default=MaterialBalanceType.componentPhase,
            domain=In(MaterialBalanceType),
            description="Material balance construction flag",
            doc="""Indicates what type of material balance should be constructed,
**default** - MaterialBalanceType.componentPhase.
**Valid values:** {
**MaterialBalanceType.none** - exclude material balances,
**MaterialBalanceType.componentPhase** - use phase component balances,
**MaterialBalanceType.componentTotal** - use total component balances,
**MaterialBalanceType.elementTotal** - use total element balances,
**MaterialBalanceType.total** - use total material balance.}"""))
    CONFIG.declare(
        "energy_balance_type",
        ConfigValue(
            default=EnergyBalanceType.enthalpyTotal,
            domain=In(EnergyBalanceType),
            description="Energy balance construction flag",
            doc="""Indicates what type of energy balance should be constructed,
**default** - EnergyBalanceType.enthalpyTotal.
**Valid values:** {
**EnergyBalanceType.none** - exclude energy balances,
**EnergyBalanceType.enthalpyTotal** - single ethalpy balance for material,
**EnergyBalanceType.enthalpyPhase** - ethalpy balances for each phase,
**EnergyBalanceType.energyTotal** - single energy balance for material,
**EnergyBalanceType.energyPhase** - energy balances for each phase.}"""))
    CONFIG.declare(
        "momentum_balance_type",
        ConfigValue(
            default=MomentumBalanceType.pressureTotal,
            domain=In(MomentumBalanceType),
            description="Momentum balance construction flag",
            doc="""Indicates what type of momentum balance should be constructed,
**default** - MomentumBalanceType.pressureTotal.
**Valid values:** {
**MomentumBalanceType.none** - exclude momentum balances,
**MomentumBalanceType.pressureTotal** - single pressure balance for material,
**MomentumBalanceType.pressurePhase** - pressure balances for each phase,
**MomentumBalanceType.momentumTotal** - single momentum balance for material,
**MomentumBalanceType.momentumPhase** - momentum balances for each phase.}"""))
    CONFIG.declare(
        "has_heat_transfer",
        ConfigValue(
            default=False,
            domain=In([True, False]),
            description="Heat transfer term construction flag",
            doc=
            """Indicates whether terms for heat transfer should be constructed,
**default** - False.
**Valid values:** {
**True** - include heat transfer terms,
**False** - exclude heat transfer terms.}"""))
    CONFIG.declare(
        "has_pressure_change",
        ConfigValue(
            default=False,
            domain=In([True, False]),
            description="Pressure change term construction flag",
            doc="""Indicates whether terms for pressure change should be
constructed,
**default** - False.
**Valid values:** {
**True** - include pressure change terms,
**False** - exclude pressure change terms.}"""))
    CONFIG.declare(
        "property_package",
        ConfigValue(
            default=useDefault,
            domain=is_physical_parameter_block,
            description="Property package to use for control volume",
            doc=
            """Property parameter object used to define property calculations,
**default** - useDefault.
**Valid values:** {
**useDefault** - use default package from parent model or flowsheet,
**PhysicalParameterObject** - a PhysicalParameterBlock object.}"""))
    CONFIG.declare(
        "property_package_args",
        ConfigBlock(
            implicit=True,
            description="Arguments to use for constructing property packages",
            doc=
            """A ConfigBlock with arguments to be passed to a property block(s)
and used when constructing these,
**default** - None.
**Valid values:** {
see property package for documentation.}"""))
    CONFIG.declare(
        "finite_elements",
        ConfigValue(
            default=5,
            domain=int,
            description="Number of finite elements length domain",
            doc="""Number of finite elements to use when discretizing length
domain (default=5). Should set to the number of tube rows"""))
    CONFIG.declare(
        "collocation_points",
        ConfigValue(
            default=3,
            domain=int,
            description="Number of collocation points per finite element",
            doc="""Number of collocation points to use per finite element when
discretizing length domain (default=3)"""))
    CONFIG.declare(
        "inside_diameter",
        ConfigValue(default=1.0,
                    description='inside diameter of drum',
                    doc='define inside diameter of drum'))

    CONFIG.declare(
        "thickness",
        ConfigValue(default=0.1,
                    description='drum wall thickness',
                    doc='define drum wall thickness'))

    def build(self):
        """
        Begin building model (pre-DAE transformation).
        Args:
            None
        Returns:
            None
        """

        # Call UnitModel.build to setup dynamics
        super(Drum1DData, self).build()

        # Build Control Volume
        self.control_volume = ControlVolume0DBlock(
            default={
                "dynamic": self.config.dynamic,
                "has_holdup": self.config.has_holdup,
                "property_package": self.config.property_package,
                "property_package_args": self.config.property_package_args
            })

        self.control_volume.add_geometry()

        self.control_volume.add_state_blocks(has_phase_equilibrium=False)

        self.control_volume.add_material_balances(
            balance_type=self.config.material_balance_type,
            has_rate_reactions=False,
            has_equilibrium_reactions=False)

        self.control_volume.add_energy_balances(
            balance_type=self.config.energy_balance_type,
            has_heat_of_reaction=False,
            has_heat_transfer=self.config.has_heat_transfer)

        self.control_volume.add_momentum_balances(
            balance_type=self.config.momentum_balance_type,
            has_pressure_change=True)

        # Add Ports
        self.add_inlet_port()
        self.add_outlet_port()

        # Add object references
        add_object_reference(self, "volume", self.control_volume.volume)

        # Set references to balance terms at unit level
        if (self.config.has_heat_transfer is True
                and self.config.energy_balance_type != EnergyBalanceType.none):
            add_object_reference(self, "heat_duty", self.control_volume.heat)

        if (self.config.has_pressure_change is True
                and self.config.momentum_balance_type != 'none'):
            add_object_reference(self, "deltaP", self.control_volume.deltaP)

        # Set Unit Geometry and Holdup Volume
        self._set_geometry()

        # Construct performance equations
        self._make_performance()

    def _set_geometry(self):
        """
        Define the geometry of the unit as necessary
        """

        # Constant pi
        self.pi = Param(initialize=math.pi, doc="Pi")
        # Constant gravity
        self.gravity = Param(initialize=9.806, doc="Gravity")

        di = self.config.inside_diameter
        thk = self.config.thickness

        # Inside diameter of drum
        self.diameter_drum = Param(initialize=di,
                                   doc="Inside diameter of drum")
        # Thickness of drum wall
        self.thickness_drum = Param(initialize=thk,
                                    doc="wall thickness of drum")
        # Thickness of insulation layer
        self.thickness_insulation = Var(initialize=0.2,
                                        doc="Insulation layer thickness")
        # Length of drum
        self.length_drum = Var(initialize=10, doc="Horizontal length of drum")
        # Number of downcomers connected at the bottom of drum, used to calculate contrac
        self.count_downcomer = Var(
            initialize=4, doc="Number of downcomers connected to drum")
        # Inside diameter of downcomer
        self.diameter_downcomer = Var(initialize=0.6,
                                      doc="Inside diameter of downcomer")

        # Inside Radius expression
        @self.Expression(doc="Inside radius of drum")
        def rin_drum(b):
            return 0.5 * b.diameter_drum

        # Outside Radius expression
        @self.Expression(doc="Outside radius of drum")
        def rout_drum(b):
            return b.rin_drum + b.thickness_drum

        # Outside diameter expression
        @self.Expression(doc="Outside radius of drum")
        def dout_drum(b):
            return b.diameter_drum + 2 * b.thickness_drum

        # Inner surface area (ignore two hemispheres at ends)
        @self.Expression(doc="Inner surface area")
        def area_drum(b):
            return b.pi * b.diameter_drum * b.length_drum

    def _make_performance(self):
        """
        Define constraints which describe the behaviour of the unit model.
        """

        # thermal conductivity of drum
        self.cond_therm_metal = Param(initialize=40, mutable=True)

        # thermal conductivity of insulation
        self.cond_therm_insulation = Param(initialize=0.08, mutable=True)

        # thermal conductivity of air
        self.cond_therm_air = Param(initialize=0.03, mutable=True)

        # thermal diffusivity of drum
        #self.diff_therm_metal = Param(initialize = 9.5E-6, mutable=True)

        # material density of drum
        self.density_thermal_metal = Param(initialize=7753, mutable=True)

        # heat capacity of drum
        self.heat_capacity_thermal_drum = Param(initialize=486, mutable=True)

        # Young modulus
        self.Young_modulus = Param(initialize=2.07E5, mutable=True)

        # Poisson's ratio
        self.Poisson_ratio = Param(initialize=0.292, mutable=True)

        # Coefficient of thermal expansion
        self.coefficient_therm_expansion = Param(initialize=1.4E-5,
                                                 mutable=True)

        # constant related to Ra, (gravity*expansion_coefficient*density/viscosity/thermal_diffusivity)^(1/6)
        # use properties at 50 C and 1 atm, 6.84e7^(1/6)=20.223
        self.const_Ra_root6 = Param(initialize=20.223, mutable=True)

        # constant related to Nu for free convection, 0.387/(1+0.721*Pr^(-9/16))^(8/27)
        # use properties at 50 C and 1 atm
        self.const_Nu = Param(initialize=0.322, mutable=True)

        # ambient pressure
        self.pres_amb = Param(initialize=0.81E5, doc="ambient pressure")

        # ambient temperature
        self.temp_amb = Var(self.flowsheet().config.time,
                            initialize=300,
                            doc="ambient temperature")

        # inside heat transfer coefficient
        self.h_in = Var(self.flowsheet().config.time,
                        initialize=1,
                        doc="inside heat transfer coefficient")

        # outside heat transfer coefficient
        self.h_out = Var(self.flowsheet().config.time,
                         initialize=1,
                         doc="outside heat transfer coefficient")

        # insulation free convection heat transfer coefficient
        self.h_free_conv = Var(
            self.flowsheet().config.time,
            initialize=1,
            doc="insulation free convection heat transfer coefficient")

        # Ra number of free convection
        self.N_Ra_root6 = Var(
            self.flowsheet().config.time,
            initialize=80,
            doc="1/6 power of Ra number of free convection of air")

        # Nu number  of free convection
        self.N_Nu = Var(self.flowsheet().config.time,
                        initialize=1,
                        doc="Nu number of free convection of air")

        # Define the continuous domains for model
        self.r = ContinuousSet(bounds=(self.rin_drum, self.rout_drum))

        # Temperature across wall thickness
        self.T = Var(self.flowsheet().config.time,
                     self.r,
                     bounds=(280, 800),
                     initialize=550)

        # Declare derivatives in the model
        if self.config.dynamic is True:
            self.dTdt = DerivativeVar(self.T, wrt=self.flowsheet().config.time)
        self.dTdr = DerivativeVar(self.T, wrt=self.r)
        self.d2Tdr2 = DerivativeVar(self.T, wrt=(self.r, self.r))

        discretizer = TransformationFactory('dae.finite_difference')
        discretizer.apply_to(self,
                             nfe=self.config.finite_elements,
                             wrt=self.r,
                             scheme='CENTRAL')

        # Add performance variables
        self.level = Var(self.flowsheet().config.time,
                         initialize=1.0,
                         doc='Water level from the bottom of the drum')

        # Velocity of fluid inside downcomer pipe
        self.velocity_downcomer = Var(
            self.flowsheet().config.time,
            initialize=10.0,
            doc='Liquid water velocity at the top of downcomer')

        # Pressure change due to contraction
        self.deltaP_contraction = Var(self.flowsheet().config.time,
                                      initialize=-1.0,
                                      doc='Pressure change due to contraction')

        # Pressure change due to gravity
        self.deltaP_gravity = Var(self.flowsheet().config.time,
                                  initialize=1.0,
                                  doc='Pressure change due to gravity')

        # thermal diffusivity of drum
        @self.Expression(doc="Thermal diffusivity of drum")
        def diff_therm_metal(b):
            return b.cond_therm_metal / (b.density_thermal_metal *
                                         b.heat_capacity_thermal_drum)

        # Expressure for the angle from the drum center to the circumference point at water level
        @self.Expression(self.flowsheet().config.time,
                         doc="angle of water level")
        def alpha_drum(b, t):
            return asin((b.level[t] - b.rin_drum) / b.rin_drum)

        # Expressure for the fraction of wet area
        @self.Expression(self.flowsheet().config.time,
                         doc="fraction of wet area")
        def frac_wet_area(b, t):
            return (b.alpha_drum[t] + b.pi / 2) / b.pi

        # Constraint for volume liquid in drum
        @self.Constraint(self.flowsheet().config.time,
                         doc="volume of liquid in drum")
        def volume_eqn(b, t):
            return b.volume[t] == \
                   ((b.alpha_drum[t]+0.5*b.pi)*b.rin_drum**2 + \
                   b.rin_drum*cos(b.alpha_drum[t])*(b.level[t]-b.rin_drum))* \
                   b.length_drum

        # Equation for velocity at the entrance of downcomer
        @self.Constraint(self.flowsheet().config.time,
                         doc="Vecolity at entrance of downcomer")
        def velocity_eqn(b, t):
            return b.velocity_downcomer[t]*0.25*b.pi*b.diameter_downcomer**2*b.count_downcomer \
                   == b.control_volume.properties_out[t].flow_vol

        # Pressure change equation for contraction, -0.5*1/2*density*velocity^2 for stagnation head loss
        # plus 1/2*density*velocity^2 dynamic head (acceleration pressure change)
        @self.Constraint(self.flowsheet().config.time,
                         doc="pressure change due to contraction")
        def pressure_change_contraction_eqn(b, t):
            return b.deltaP_contraction[t] == \
                   -0.75 * b.control_volume.properties_out[t].dens_mass_phase["Liq"] * \
                   b.velocity_downcomer[t]**2

        # Pressure change equation for gravity, density*gravity*height
        @self.Constraint(self.flowsheet().config.time,
                         doc="pressure change due to gravity")
        def pressure_change_gravity_eqn(b, t):
            return b.deltaP_gravity[t] == \
                   b.control_volume.properties_out[t].dens_mass_phase["Liq"] * b.gravity * b.level[t]

        # Total pressure change equation
        @self.Constraint(self.flowsheet().config.time, doc="pressure drop")
        def pressure_change_total_eqn(b, t):
            return b.deltaP[t] == b.deltaP_contraction[t] + b.deltaP_gravity[t]

        # Constraint for heat conduction equation
        @self.Constraint(self.flowsheet().config.time,
                         self.r,
                         doc="1-D heat conduction equation through radius")
        def heat_conduction_eqn(b, t, r):
            if r == b.r.first() or r == b.r.last():
                return Constraint.Skip
            if self.config.dynamic is True:
                return b.dTdt[t, r] == b.diff_therm_metal * b.d2Tdr2[
                    t, r] + b.diff_therm_metal * (1 / r) * b.dTdr[t, r]
            else:
                return 0 == b.diff_therm_metal * b.d2Tdr2[
                    t, r] + b.diff_therm_metal * (1 / r) * b.dTdr[t, r]

        @self.Constraint(self.flowsheet().config.time, doc="inner wall BC")
        def inner_wall_bc_eqn(b, t):
            return b.h_in[t]*(b.control_volume.properties_out[t].temperature - b.T[t,b.r.first()]) == \
                   -b.dTdr[t,b.r.first()]*b.cond_therm_metal

        @self.Constraint(self.flowsheet().config.time, doc="outer wall BC")
        def outer_wall_bc_eqn(b, t):
            return b.h_out[t]*(b.T[t,b.r.last()] - b.temp_amb[t]) == \
                   -b.dTdr[t, b.r.last()]*b.cond_therm_metal

        # Inner wall BC for dTdt
        @self.Constraint(self.flowsheet().config.time,
                         doc="extra inner wall temperature derivative")
        def extra_at_inner_wall_eqn(b, t):
            if self.config.dynamic is True:
                term = b.dTdt[t, b.r.first()]
            else:
                term = 0
            return term == 4*b.diff_therm_metal*(b.r.first()+b.r[2])/ \
                (b.r[2]-b.r.first())**2/(3*b.r.first()+b.r[2])*(b.T[t,b.r[2]] \
                -b.T[t,b.r.first()]) + 8*b.diff_therm_metal/b.cond_therm_metal*b.h_in[t]*b.r.first()/ \
                (b.r[2]-b.r.first())/(3*b.r.first()+b.r[2])*(b.control_volume.properties_out[t].temperature \
                -b.T[t,b.r.first()])

        @self.Constraint(self.flowsheet().config.time,
                         doc="extra outer wall temperature derivative")
        def extra_at_outer_wall_eqn(b, t):
            if self.config.dynamic is True:
                term = b.dTdt[t, b.r.last()]
            else:
                term = 0
            return term == 4*b.diff_therm_metal*(b.r.last()+b.r[-2])/ \
                (b.r.last()-b.r[-2])**2/(3*b.r.last()+b.r[-2])*(b.T[t,b.r[-2]] \
                -b.T[t,b.r.last()]) + 8*b.diff_therm_metal/b.cond_therm_metal*b.h_out[t]*b.r.last()/ \
                (b.r.last()-b.r[-2])/(3*b.r.last()+b.r[-2])*(b.temp_amb[t] \
                -b.T[t,b.r.last()])

        # reduced pressure expression
        @self.Expression(self.flowsheet().config.time, doc="reduced pressure")
        def pres_reduced(b, t):
            return b.control_volume.properties_out[t].pressure / 2.2048e7

        # calculate inner side heat transfer coefficient with minimum temperature difference set to sqrt(0.1)
        # multipling wet area fraction to convert it to the value based on total circumference
        @self.Constraint(self.flowsheet().config.time,
                         doc="inner side heat transfer coefficient")
        def h_in_eqn(b, t):
            return b.h_in[t] == 2178.6*(b.control_volume.properties_out[t].pressure/2.2048e7)**0.36\
                   /(-log10(b.control_volume.properties_out[t].pressure/2.2048e7))**1.65 *\
                   (0.1+(b.control_volume.properties_out[t].temperature-b.T[t,b.r.first()])**2)*b.frac_wet_area[t]

        # Expressure for insulation heat transfer (conduction) resistance based on drum metal outside diameter
        @self.Expression(doc="heat transfer resistance of insulation layer")
        def resistance_insulation(b):
            return b.rout_drum * log((b.rout_drum + b.thickness_insulation) /
                                     b.rout_drum) / b.cond_therm_insulation

        # h_out equation considering conduction through insulation and free convection between insulation and ambient
        @self.Constraint(self.flowsheet().config.time,
                         doc="outer side heat transfer coefficient")
        def h_out_eqn(b, t):
            return b.h_out[t] * (b.resistance_insulation +
                                 1 / b.h_free_conv[t]) == 1.0

        # Expressure for outside insulation wall temperature (skin temperature)
        @self.Expression(self.flowsheet().config.time,
                         doc="outside insulation wall temperature")
        def temp_insulation_outside(b, t):
            return b.temp_amb[t] + (b.T[t, b.r.last()] - b.temp_amb[t]
                                    ) * b.h_out[t] / b.h_free_conv[t]

        # Ra number equation
        @self.Constraint(self.flowsheet().config.time,
                         doc="Ra number of free convection")
        def Ra_number_eqn(b, t):
            return b.N_Ra_root6[t] == b.const_Ra_root6 * sqrt(
                b.dout_drum + 2 * b.thickness_insulation) * (
                    b.T[t, b.r.last()] - b.temp_amb[t])**0.166667

        # Nu number equation
        @self.Constraint(self.flowsheet().config.time,
                         doc=" Nu number of free convection")
        def Nu_number_eqn(b, t):
            return b.N_Nu[t] == (0.6 + b.const_Nu * b.N_Ra_root6[t])**2

        # free convection coefficient based on the drum metal outside diameter
        @self.Constraint(
            self.flowsheet().config.time,
            doc=
            "free convection heat transfer coefficient between insulation wall and ambient"
        )
        def h_free_conv_eqn(b, t):
            return b.h_free_conv[
                t] == b.N_Nu[t] * b.cond_therm_air / b.dout_drum

        @self.Constraint(self.flowsheet().config.time,
                         doc="heat loss of water")
        def heat_loss_eqn(b, t):
            return b.heat_duty[t] == b.area_drum*b.h_in[t]*(b.T[t,b.r.first()]\
                   -b.control_volume.properties_out[t].temperature)

        ### Calculate mechanical and thermal stresses
        # ----------------------------------------------------------------------------------------------

        # Integer indexing for radius domain
        self.rindex = Param(self.r,
                            initialize=1,
                            mutable=True,
                            doc="inter indexing for radius domain")

        # calculate integral point for mean temperature in the wall
        @self.Expression(self.flowsheet().config.time,
                         doc="integral point used to estimate mean temperature"
                         )
        def int_mean_temp(b, t):
            return 2*(b.r[2]-b.r[1])/(b.rout_drum**2-b.rin_drum**2)*(sum(0.5*(b.r[i-1]*b.T[t,b.r[i-1]]+\
                b.r[i]*b.T[t,b.r[i]]) for i in range(2,len(b.r)+1)))

        for index_r, value_r in enumerate(self.r, 1):
            self.rindex[value_r] = index_r

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="integral point at each element")
        def int_temp(b, t, r):
            if b.rindex[r].value == 1:
                return b.T[t, b.r.first()]
            else:
                return 2*(b.r[2]-b.r[1])/(b.r[b.rindex[r].value]**2-b.rin_drum**2)\
                *(sum(0.5*(b.r[j-1]*b.T[t,b.r[j-1]]+b.r[j]*b.T[t,b.r[j]])\
                 for j in range(2,b.rindex[r].value+1)))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at radial direction")
        def therm_stress_radial(b, t, r):
            return 0.5*b.Young_modulus*b.coefficient_therm_expansion/(1-b.Poisson_ratio)\
            *((1-b.rin_drum**2/r**2)*(b.int_mean_temp[t]-b.int_temp[t,r]))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at circumferential direction")
        def therm_stress_circumferential(b, t, r):
            return 0.5*b.Young_modulus*b.coefficient_therm_expansion/(1-b.Poisson_ratio)\
                *((1+b.rin_drum**2/r**2)*b.int_mean_temp[t]+(1-b.rin_drum**2/r**2)*b.int_temp[t,r]-2*b.T[t,r])

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="thermal stress at axial direction")
        def therm_stress_axial(b, t, r):
            return b.Young_modulus * b.coefficient_therm_expansion / (
                1 - b.Poisson_ratio) * (b.int_mean_temp[t] - b.T[t, r])

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at radial direction")
        def mech_stress_radial(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2)+(1E-5*(b.pres_amb-b.control_volume.properties_out[t].pressure)\
                *b.rin_drum**2*b.rout_drum**2/(r**2*(b.rout_drum**2-b.rin_drum**2))))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at circumferential direction")
        def mech_stress_circumferential(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2)-(1E-5*(b.pres_amb-b.control_volume.properties_out[t].pressure)\
                    *b.rin_drum**2*b.rout_drum**2/(r**2*(b.rout_drum**2-b.rin_drum**2))))

        @self.Expression(self.flowsheet().config.time,
                         self.r,
                         doc="mechanical stress at axial direction")
        def mech_stress_axial(b, t, r):
            return 0.1*(1E-5*(b.control_volume.properties_out[t].pressure*b.rin_drum**2-b.pres_amb*b.rout_drum**2)\
                /(b.rout_drum**2-b.rin_drum**2))

    def set_initial_condition(self):
        if self.config.dynamic is True:
            self.control_volume.material_accumulation[:, :, :].value = 0
            self.control_volume.energy_accumulation[:, :].value = 0
            self.dTdt[:, :].value = 0
            self.control_volume.material_accumulation[0, :, :].fix(0)
            self.control_volume.energy_accumulation[0, :].fix(0)
            self.dTdt[0, :].fix(0)

    def initialize(blk,
                   state_args={},
                   outlvl=0,
                   solver='ipopt',
                   optarg={'tol': 1e-6}):
        '''
        Drum1D initialization routine.

        Keyword Arguments:
            state_args : a dict of arguments to be passed to the property
                           package(s) for the control_volume of the model to
                           provide an initial state for initialization
                           (see documentation of the specific property package)
                           (default = {}).
            outlvl : sets output level of initialisation routine

                     * 0 = no output (default)
                     * 1 = return solver state for each step in routine
                     * 2 = return solver state for each step in subroutines
                     * 3 = include solver output infomation (tee=True)

            optarg : solver options dictionary object (default={'tol': 1e-6})
            solver : str indicating whcih solver to use during
                     initialization (default = 'ipopt')

        Returns:
            None
        '''
        init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="unit")
        solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="unit")

        opt = SolverFactory(solver)
        opt.options = optarg

        flags = blk.control_volume.initialize(outlvl=outlvl + 1,
                                              optarg=optarg,
                                              solver=solver,
                                              state_args=state_args)
        init_log.info_high("Initialization Step 1 Complete.")

        # set initial values for T
        r_mid = value((blk.r.first() + blk.r.last()) / 2)
        # assume outside wall temperature is 10 K lower than fluid temperature
        T_out = value(blk.control_volume.properties_in[0].temperature - 1)
        T_mid = value(
            (T_out + blk.control_volume.properties_in[0].temperature) / 2)
        slope = value((T_out-blk.control_volume.properties_in[0].temperature)/ \
                      (blk.r.last()-blk.r.first())/3)
        for x in blk.r:
            blk.T[:, x].fix(T_mid + slope * (x - r_mid))
        blk.T[:, :].unfix()

        # Fix outlet enthalpy and pressure
        for t in blk.flowsheet().config.time:
            blk.control_volume.properties_out[t].pressure.fix(value(blk.control_volume.properties_in[0].pressure) \
            - 5000.0)
            blk.control_volume.properties_out[t].enth_mol.fix(
                value(blk.control_volume.properties_in[0].enth_mol))
        blk.pressure_change_total_eqn.deactivate()
        blk.heat_loss_eqn.deactivate()

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = opt.solve(blk, tee=slc.tee)
        init_log.info_high("Initialization Step 2 {}.".format(
            idaeslog.condition(res)))

        # Unfix outlet enthalpy and pressure
        for t in blk.flowsheet().config.time:
            blk.control_volume.properties_out[t].pressure.unfix()
            blk.control_volume.properties_out[t].enth_mol.unfix()
        blk.pressure_change_total_eqn.activate()
        blk.heat_loss_eqn.activate()

        with idaeslog.solver_log(solve_log, idaeslog.DEBUG) as slc:
            res = opt.solve(blk, tee=slc.tee)
        init_log.info_high("Initialization Step 2 {}.".format(
            idaeslog.condition(res)))

        blk.control_volume.release_state(flags, outlvl - 1)
        init_log.info("Initialization Complete.")

    def calculate_scaling_factors(self):
        for v in self.deltaP_gravity.values():
            if iscale.get_scaling_factor(v, warning=True) is None:
                iscale.set_scaling_factor(v, 1e-3)

        for v in self.deltaP_contraction.values():
            if iscale.get_scaling_factor(v, warning=True) is None:
                iscale.set_scaling_factor(v, 1e-3)

        for t, c in self.heat_loss_eqn.items():
            sf = iscale.get_scaling_factor(self.heat_duty[t],
                                           default=1,
                                           warning=True)
            iscale.constraint_scaling_transform(c, sf)

        for t, c in self.pressure_change_contraction_eqn.items():
            sf = iscale.get_scaling_factor(self.deltaP_contraction[t],
                                           default=1,
                                           warning=True)
            iscale.constraint_scaling_transform(c, sf)

        for t, c in self.pressure_change_gravity_eqn.items():
            sf = iscale.get_scaling_factor(self.deltaP_gravity[t],
                                           default=1,
                                           warning=True)
            iscale.constraint_scaling_transform(c, sf)

        for t, c in self.pressure_change_total_eqn.items():
            sf = iscale.get_scaling_factor(self.deltaP[t],
                                           default=1,
                                           warning=True)
            iscale.constraint_scaling_transform(c, sf)
Exemple #27
0
 def Xtest_list_domain_empty(self):
     with self.assertRaises(ValueError) as cm:
         self.model = ConcreteModel()
         self.model.y = Var([1, 2], within=[])
Exemple #28
0
    def test_nonnegativity_transformation_2(self):
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals)
        self.model.y3 = Var(self.model.S, domain=NegativeIntegers)
        self.model.z3 = Var(self.model.S, self.model.T, domain=Reals)

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1 or args[0] == 0:
                return NonNegativeReals
            elif args[0] == 1:
                return NonNegativeIntegers
            elif args[0] == 2:
                return NonPositiveReals
            elif args[0] == 3:
                return NonPositiveIntegers
            elif args[0] == 4:
                return NegativeReals
            elif args[0] == 5:
                return NegativeIntegers
            elif args[0] == 6:
                return PositiveReals
            elif args[0] == 7:
                return PositiveIntegers
            elif args[0] == 8:
                return Reals
            elif args[0] == 9:
                return Integers
            elif args[0] == 10:
                return Binary
            else:
                return NonNegativeReals

        self.model.x4 = Var(domain=domainRule)
        self.model.y4 = Var(self.model.S, domain=domainRule)
        self.model.z4 = Var(self.model.S, self.model.T, domain=domainRule)

        instance = self.model.create_instance()
        xfrm = TransformationFactory('core.nonnegative_vars')
        transformed = xfrm.create_using(instance)

        # Make sure everything is nonnegative
        for c in ('x', 'y', 'z'):
            for n in ('1', '2', '3', '4'):
                var = transformed.__getattribute__(c + n)
                for ndx in var._index:
                    self.assertTrue(self.nonnegativeBounds(var[ndx]))
Exemple #29
0
 def Xtest_list_domain_bad_duplicates(self):
     with self.assertRaises(ValueError) as cm:
         self.model = ConcreteModel()
         self.model.y = Var([1, 2], within=[1, 1, 2, 3])
Exemple #30
0
    def test_nonnegative_transform_3(self):
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals, bounds=(-10, 10))
        self.model.y3 = Var(self.model.S,
                            domain=NegativeIntegers,
                            bounds=(-10, 10))
        self.model.z3 = Var(self.model.S,
                            self.model.T,
                            domain=Reals,
                            bounds=(-10, 10))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1:
                arg = 0
            else:
                arg = args[1]

            if len(args) == 1 or arg == 0:
                return NonNegativeReals
            elif arg == 1:
                return NonNegativeIntegers
            elif arg == 2:
                return NonPositiveReals
            elif arg == 3:
                return NonPositiveIntegers
            elif arg == 4:
                return NegativeReals
            elif arg == 5:
                return NegativeIntegers
            elif arg == 6:
                return PositiveReals
            elif arg == 7:
                return PositiveIntegers
            elif arg == 8:
                return Reals
            elif arg == 9:
                return Integers
            elif arg == 10:
                return Binary
            else:
                return Reals

        self.model.x4 = Var(domain=domainRule, bounds=(-10, 10))
        self.model.y4 = Var(self.model.S, domain=domainRule, bounds=(-10, 10))
        self.model.z4 = Var(self.model.S,
                            self.model.T,
                            domain=domainRule,
                            bounds=(-10, 10))

        def objRule(model):
            return sum(5*sum_product(model.__getattribute__(c+n)) \
                       for c in ('x', 'y', 'z') for n in ('1', '2', '3', '4'))

        self.model.obj = Objective(rule=objRule)

        transform = TransformationFactory('core.nonnegative_vars')
        instance = self.model.create_instance()
        transformed = transform.create_using(instance)

        opt = SolverFactory("glpk")

        instance_sol = opt.solve(instance)
        transformed_sol = opt.solve(transformed)

        self.assertEqual(
            instance_sol["Solution"][0]["Objective"]['obj']["value"],
            transformed_sol["Solution"][0]["Objective"]['obj']["value"])
Exemple #31
0
    def test_standard_form_transform_2(self):
        """ Same as #1, but adds constraints """
        self.model.S = RangeSet(0, 10)
        self.model.T = Set(initialize=["foo", "bar"])

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit bounds
        self.model.x1 = Var(bounds=(-3, 3))
        self.model.y1 = Var(self.model.S, bounds=(-3, 3))
        self.model.z1 = Var(self.model.S, self.model.T, bounds=(-3, 3))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined bounds
        def boundsRule(*args):
            return (-4, 4)

        self.model.x2 = Var(bounds=boundsRule)
        self.model.y2 = Var(self.model.S, bounds=boundsRule)
        self.model.z2 = Var(self.model.S, self.model.T, bounds=boundsRule)

        # Unindexed, singly indexed, and doubly indexed variables with
        # explicit domains
        self.model.x3 = Var(domain=NegativeReals, bounds=(-10, 10))
        self.model.y3 = Var(self.model.S,
                            domain=NegativeIntegers,
                            bounds=(-10, 10))
        self.model.z3 = Var(self.model.S,
                            self.model.T,
                            domain=Reals,
                            bounds=(-10, 10))

        # Unindexed, singly indexed, and doubly indexed variables with
        # rule-defined domains
        def domainRule(*args):
            if len(args) == 1:
                arg = 0
            else:
                arg = args[1]

            if len(args) == 1 or arg == 0:
                return NonNegativeReals
            elif arg == 1:
                return NonNegativeIntegers
            elif arg == 2:
                return NonPositiveReals
            elif arg == 3:
                return NonPositiveIntegers
            elif arg == 4:
                return NegativeReals
            elif arg == 5:
                return NegativeIntegers
            elif arg == 6:
                return PositiveReals
            elif arg == 7:
                return PositiveIntegers
            elif arg == 8:
                return Reals
            elif arg == 9:
                return Integers
            elif arg == 10:
                return Binary
            else:
                return Reals

        self.model.x4 = Var(domain=domainRule, bounds=(-10, 10))
        self.model.y4 = Var(self.model.S, domain=domainRule, bounds=(-10, 10))
        self.model.z4 = Var(self.model.S,
                            self.model.T,
                            domain=domainRule,
                            bounds=(-10, 10))

        # Add some constraints
        def makeXConRule(var):
            def xConRule(model, var):
                return (-1, var, 1)

        def makeYConRule(var):
            def yConRule(model, var, s):
                return (-1, var[s], 1)

        def makeZConRule(var):
            def zConRule(model, var, s, t):
                return (-1, var[s, t], 1)

        for n in ('1', '2', '3', '4'):
            self.model.__setattr__(
                "x" + n + "_constraint",
                Constraint(
                    rule=makeXConRule(self.model.__getattribute__("x" + n))))

            self.model.__setattr__(
                "y" + n + "_constraint",
                Constraint(
                    rule=makeYConRule(self.model.__getattribute__("y" + n))))

            self.model.__setattr__(
                "z" + n + "_constraint",
                Constraint(
                    rule=makeZConRule(self.model.__getattribute__("z" + n))))

        def objRule(model):
            return sum(5*sum_product(model.__getattribute__(c+n)) \
                       for c in ('x', 'y', 'z') for n in ('1', '2', '3', '4'))

        self.model.obj = Objective(rule=objRule)

        transform = StandardForm()
        instance = self.model.create_instance()
        transformed = transform(instance)

        opt = SolverFactory("glpk")

        instance_sol = opt.solve(instance)
        transformed_sol = opt.solve(transformed)

        self.assertEqual(
            instance_sol["Solution"][0]["Objective"]['obj']["value"],
            transformed_sol["Solution"][0]["Objective"]['obj']["value"])
Exemple #32
0
    def build(self):
        """
        Build the PID block
        """
        super().build()

        # Do nothing if steady-state
        if self.config.dynamic is True:
            # Check for required config
            if self.config.pv is None:
                raise ConfigurationError("Controller configuration"
                                         " requires 'pv'")
            if self.config.mv is None:
                raise ConfigurationError("Controller configuration"
                                         " requires 'mv'")
            # Shorter pointers to time set information
            time_set = self.flowsheet().time
            self.pv = Reference(self.config.pv)
            self.mv = Reference(self.config.mv)

            # Parameters
            self.mv_lb = Param(mutable=True,
                               initialize=0.05,
                               doc="Controller output lower bound")
            self.mv_ub = Param(mutable=True,
                               initialize=1,
                               doc="Controller output upper bound")

            # Variable for basic controller settings may change with time.
            self.setpoint = Var(time_set, initialize=0.5, doc="Setpoint")
            self.gain_p = Var(time_set,
                              initialize=0.1,
                              doc="Gain for proportional part")
            if self.config.type == 'PI' or self.config.type == 'PID':
                self.gain_i = Var(time_set,
                                  initialize=0.1,
                                  doc="Gain for integral part")
            if self.config.type == 'PD' or self.config.type == 'PID':
                self.gain_d = Var(time_set,
                                  initialize=0.01,
                                  doc="Gain for derivative part")
            self.mv_ref = Var(initialize=0.5,
                              doc="bias value of manipulated variable")

            if self.config.type == 'P' or self.config.type == 'PI':

                @self.Expression(time_set, doc="Error expression")
                def error(b, t):
                    return b.setpoint[t] - b.pv[t]
            else:
                self.error = Var(time_set, initialize=0, doc="Error variable")

                @self.Constraint(time_set, doc="Error variable")
                def error_eqn(b, t):
                    return b.error[t] == b.setpoint[t] - b.pv[t]

            if self.config.type == 'PI' or self.config.type == 'PID':
                self.integral_of_error = Var(time_set,
                                             initialize=0,
                                             doc="Integral term")
                self.error_from_integral = DerivativeVar(
                    self.integral_of_error,
                    wrt=self.flowsheet().time,
                    initialize=0)

                @self.Constraint(time_set,
                                 doc="Error calculated by"
                                 " derivative of integral")
                def error_from_integral_eqn(b, t):
                    return b.error[t] == b.error_from_integral[t]

            if self.config.type == 'PID' or self.config.type == 'PD':
                self.derivative_of_error = DerivativeVar(
                    self.error, wrt=self.flowsheet().time, initialize=0)

            @self.Expression(time_set, doc="Proportional output")
            def mv_p_only(b, t):
                return b.gain_p[t] * b.error[t]

            @self.Expression(time_set, doc="Proportional output and reference")
            def mv_p_only_with_ref(b, t):
                return b.gain_p[t] * b.error[t] + b.mv_ref

            if self.config.type == 'PI' or self.config.type == 'PID':

                @self.Expression(time_set, doc="Integral output")
                def mv_i_only(b, t):
                    return b.gain_i[t] * b.integral_of_error[t]

            if self.config.type == 'PD' or self.config.type == 'PID':

                @self.Expression(time_set, doc="Derivative output")
                def mv_d_only(b, t):
                    return b.gain_d[t] * b.derivative_of_error[t]

            @self.Expression(time_set,
                             doc="Unbounded output for manimulated variable")
            def mv_unbounded(b, t):
                if self.config.type == 'PID':
                    return (b.mv_ref + b.gain_p[t] * b.error[t] +
                            b.gain_i[t] * b.integral_of_error[t] +
                            b.gain_d[t] * b.derivative_of_error[t])
                elif self.config.type == 'PI':
                    return (b.mv_ref + b.gain_p[t] * b.error[t] +
                            b.gain_i[t] * b.integral_of_error[t])
                elif self.config.type == 'PD':
                    return (b.mv_ref + b.gain_p[t] * b.error[t] +
                            b.gain_d[t] * b.derivative_of_error[t])
                else:
                    return b.mv_ref + b.gain_p[t] * b.error[t]

            @self.Constraint(time_set,
                             doc="Bounded output of manipulated variable")
            def mv_eqn(b, t):
                if t == b.flowsheet().time.first():
                    return Constraint.Skip
                else:
                    if self.config.bounded_output is True:
                        return (b.mv[t]-b.mv_lb) * \
                            (1+exp(-4/(b.mv_ub-b.mv_lb)
                                   * (b.mv_unbounded[t]
                                      - (b.mv_lb
                                         + b.mv_ub)/2))) == b.mv_ub-b.mv_lb
                    else:
                        return b.mv[t] == b.mv_unbounded[t]

            if self.config.bounded_output is True:
                if self.config.type == 'PI' or self.config.type == 'PID':

                    @self.Expression(time_set,
                                     doc="Integral error"
                                     " at error 0 and mv_ref")
                    def integral_of_error_ref(b, t):
                        return ((b.mv_lb + b.mv_ub) / 2 - b.mv_ref -
                                log((b.mv_ub - b.mv_lb) /
                                    (b.mv_ref - b.mv_lb) - 1) / 4 *
                                (b.mv_ub - b.mv_lb)) / b.gain_i[t]

                    @self.Expression(time_set,
                                     doc="Integral error at error 0 and"
                                     " output value at current mv")
                    def integral_of_error_mv(b, t):
                        return ((b.mv_lb + b.mv_ub) / 2 - b.mv_ref -
                                log((b.mv_ub - b.mv_lb) /
                                    (b.mv[t] - b.mv_lb) - 1) / 4 *
                                (b.mv_ub - b.mv_lb)) / b.gain_i[t]