Esempio n. 1
0
def root_finder():
    m = ConcreteModel()

    # Define external function methods
    m.proc_Z_liq = ExternalFunction(library=_so, function="ceos_z_liq")
    m.proc_Z_vap = ExternalFunction(library=_so, function="ceos_z_vap")
    m.proc_Z_liq_x = ExternalFunction(library=_so,
                                      function="ceos_z_liq_extend")
    m.proc_Z_vap_x = ExternalFunction(library=_so,
                                      function="ceos_z_vap_extend")

    return m
Esempio n. 2
0
    def setUp(self):
        self.m = ConcreteModel()
        self.m.z = Var(range(3), domain=Reals, initialize=2.)
        self.m.x = Var(range(2), initialize=2.)
        self.m.x[1] = 1.0

        def blackbox(a, b):
            return sin(a - b)

        def grad_blackbox(args, fixed):
            a, b = args[:2]
            return [cos(a - b), -cos(a - b)]

        self.m.bb = ExternalFunction(blackbox, grad_blackbox)

        self.m.obj = Objective(expr=(self.m.z[0] - 1.0)**2 +
                               (self.m.z[0] - self.m.z[1])**2 +
                               (self.m.z[2] - 1.0)**2 +
                               (self.m.x[0] - 1.0)**4 + (self.m.x[1] - 1.0)**6)
        self.m.c1 = Constraint(expr=(self.m.x[0] * self.m.z[0]**2 +
                                     self.m.bb(self.m.x[0], self.m.x[1]) == 2 *
                                     sqrt(2.0)))
        self.m.c2 = Constraint(expr=self.m.z[2]**4 * self.m.z[1]**2 +
                               self.m.z[1] == 8 + sqrt(2.0))
        self.config = _trf_config()
        self.ext_fcn_surrogate_map_rule = lambda comp, ef: 0
        self.interface = TRFInterface(self.m,
                                      [self.m.z[0], self.m.z[1], self.m.z[2]],
                                      self.ext_fcn_surrogate_map_rule,
                                      self.config)
Esempio n. 3
0
def delta_temperature_underwood_callback(b):
    r"""
    This is a callback for a temperature difference expression to calculate
    :math:`\Delta T` in the heat exchanger model using log-mean temperature
    difference (LMTD) approximation given by Underwood (1970).  It can be
    supplied to "delta_temperature_callback" HeatExchanger configuration option.
    This uses a cube root function that works with negative numbers returning
    the real negative root. This should always evaluate successfully. This form
    is

    .. math::

        \Delta T = \left(\frac{
            \Delta T_1^\frac{1}{3} + \Delta T_2^\frac{1}{3}}{2}\right)^3

    where :math:`\Delta T_1` is the temperature difference at the hot inlet end
    and :math:`\Delta T_2` is the temperature difference at the hot outlet end.
    """
    dT1 = b.delta_temperature_in
    dT2 = b.delta_temperature_out
    temp_units = pyunits.get_units(dT1[dT1.index_set().first()])

    # external function that ruturns the real root, for the cuberoot of negitive
    # numbers, so it will return without error for positive and negitive dT.
    b.cbrt = ExternalFunction(library=functions_lib(),
                              function="cbrt",
                              arg_units=[temp_units])

    @b.Expression(b.flowsheet().time)
    def delta_temperature(b, t):
        return ((b.cbrt(dT1[t]) + b.cbrt(dT2[t])) / 2.0)**3 * temp_units
Esempio n. 4
0
    def setUp(self):

        self.m = ConcreteModel()
        self.m.z = Var(range(3), domain=Reals, initialize=2.)
        self.m.x = Var(range(2), initialize=2.)
        self.m.x[1] = 1.0

        def blackbox(a, b):
            return sin(a - b)

        def grad_blackbox(args, fixed):
            a, b = args[:2]
            return [cos(a - b), -cos(a - b)]

        self.m.bb = ExternalFunction(blackbox, grad_blackbox)

        self.m.obj = Objective(expr=(self.m.z[0] - 1.0)**2 +
                               (self.m.z[0] - self.m.z[1])**2 +
                               (self.m.z[2] - 1.0)**2 +
                               (self.m.x[0] - 1.0)**4 + (self.m.x[1] - 1.0)**6)
        self.m.c1 = Constraint(expr=(self.m.x[0] * self.m.z[0]**2 +
                                     self.m.bb(self.m.x[0], self.m.x[1]) == 2 *
                                     sqrt(2.0)))
        self.m.c2 = Constraint(expr=self.m.z[2]**4 * self.m.z[1]**2 +
                               self.m.z[1] == 8 + sqrt(2.0))
        self.decision_variables = [self.m.z[0], self.m.z[1], self.m.z[2]]
Esempio n. 5
0
    def setUp(self):
        # Borrowed this test model from the trust region tests
        m = ConcreteModel()
        m.z = Var(range(3), domain=Reals, initialize=2.)
        m.x = Var(range(4), initialize=2.)
        m.x[1] = 1.0
        m.x[2] = 0.0
        m.x[3] = None

        m.b1 = Block()
        m.b1.e1 = Expression(expr=m.x[0] + m.x[1])
        m.b1.e2 = Expression(expr=m.x[0]/m.x[2])
        m.b1.e3 = Expression(expr=m.x[3]*m.x[1])
        m.b1.e4 = Expression(expr=log(m.x[2]))
        m.b1.e5 = Expression(expr=log(m.x[2] - 2))

        def blackbox(a,b):
            return sin(a-b)
        self.bb = ExternalFunction(blackbox)

        m.obj = Objective(
            expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
                + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6 # + m.bb(m.x[0],m.x[1])
            )
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + self.bb(m.x[0],m.x[1]) == 2*sqrt(2.0))
        m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8+sqrt(2.0))
        m.c3 = Constraint(expr=m.x[1] == 3)
        m.c4 = Constraint(expr=0 == 3/m.x[2])
        m.c5 = Constraint(expr=0 == log(m.x[2]))
        m.c6 = Constraint(expr=0 == log(m.x[2]-4))
        m.c7 = Constraint(expr=0 == log(m.x[3]))
        m.p1 = Param(mutable=True, initialize=1)
        m.c8 = Constraint(expr = m.x[1] <= 1/m.p1)
        m.p1 = 0
        self.m = m.clone()
Esempio n. 6
0
 def add_funcs(self, names=None):
     if names is None:
         names = []
     elif isinstance(names, str):
         names = [names]
     for name in names:
         if hasattr(self.blk, name):
             continue
         setattr(self.blk, name,
                 ExternalFunction(**self._external[name].kwargs()))
 def test_solve_gsl_function(self):
     DLL = find_GSL()
     if not DLL:
         self.skipTest("Could not find the amplgsl.dll library")
     model = ConcreteModel()
     model.z_func = ExternalFunction(library=DLL, function="gsl_sf_gamma")
     model.x = Var(initialize=3, bounds=(1e-5, None))
     model.o = Objective(expr=model.z_func(model.x))
     nlp = PyomoNLP(model)
     self.assertAlmostEqual(nlp.evaluate_objective(), 2, 7)
     assert "AMPLFUNC" not in os.environ
Esempio n. 8
0
 def eq_lmtd(b, t):
     dT_in = b.delta_temperature_in
     dT_out = b.delta_temperature_out
     temp_units = pyunits.get_units(dT_in)
     dT_avg = (dT_in + dT_out) / 2
     # external function that ruturns the real root, for the cuberoot of negitive
     # numbers, so it will return without error for positive and negitive dT.
     b.cbrt = ExternalFunction(library=functions_lib(),
                               function="cbrt",
                               arg_units=[temp_units**3])
     return b.lmtd == b.cbrt((dT_in * dT_out * dT_avg)) * temp_units
Esempio n. 9
0
    def _external_model(self):
        DLL = find_GSL()
        if not DLL:
            self.skipTest("Could not find the amplgsl.dll library")

        m = ConcreteModel()
        m.hypot = ExternalFunction(library=DLL, function="gsl_hypot")
        m.p = Param(initialize=1, mutable=True)
        m.x = Var(initialize=3, bounds=(1e-5, None))
        m.y = Var(initialize=3, bounds=(0, None))
        m.z = Var(initialize=1)
        m.o = Objective(expr=m.z**2 * m.hypot(m.p * m.x, m.p + m.y)**2)
        self.assertAlmostEqual(value(m.o), 25.0, 7)
        return m
Esempio n. 10
0
 def test_identify_mutable_parameters_params(self):
     m = ConcreteModel()
     m.I = RangeSet(3)
     m.a = Param(initialize=1, mutable=True)
     m.b = Param(m.I, initialize=1, mutable=True)
     m.p = Var(initialize=1)
     m.x = ExternalFunction(library='foo.so', function='bar')
     #
     # Identify variables in various algebraic expressions
     #
     self.assertEqual(list(identify_mutable_parameters(m.a)), [m.a])
     self.assertEqual(list(identify_mutable_parameters(m.b[1])), [m.b[1]])
     self.assertEqual(list(identify_mutable_parameters(m.a + m.b[1])),
                      [m.a, m.b[1]])
     self.assertEqual(list(identify_mutable_parameters(m.a**m.b[1])),
                      [m.a, m.b[1]])
     self.assertEqual(
         list(identify_mutable_parameters(m.a**m.b[1] + m.b[2])),
         [m.a, m.b[1], m.b[2]])
     self.assertEqual(
         list(
             identify_mutable_parameters(m.a**m.b[1] +
                                         m.b[2] * m.b[3] * m.b[2])),
         [m.a, m.b[1], m.b[2], m.b[3]])
     self.assertEqual(
         list(
             identify_mutable_parameters(m.a**m.b[1] +
                                         m.b[2] / m.b[3] * m.b[2])),
         [m.a, m.b[1], m.b[2], m.b[3]])
     #
     # Identify variables in the arguments to functions
     #
     self.assertEqual(
         list(
             identify_mutable_parameters(
                 m.x(m.a, 'string_param', 1, []) * m.b[1])), [m.a, m.b[1]])
     self.assertEqual(
         list(
             identify_mutable_parameters(
                 m.x(m.p, 'string_param', 1, []) * m.b[1])), [m.b[1]])
     self.assertEqual(list(identify_mutable_parameters(tanh(m.a) * m.b[1])),
                      [m.a, m.b[1]])
     self.assertEqual(list(identify_mutable_parameters(abs(m.a) * m.b[1])),
                      [m.a, m.b[1]])
     #
     # Check logic for allowing duplicates
     #
     self.assertEqual(list(identify_mutable_parameters(m.a**m.a + m.a)),
                      [m.a])
Esempio n. 11
0
def create_model():
    m = ConcreteModel()
    m.name = 'Example 2: Yoshio'

    m.x1 = Var(initialize=0)
    m.x2 = Var(bounds=(-2.0, None), initialize=0)

    m.EF = ExternalFunction(ext_fcn, grad_ext_fcn)

    @m.Constraint()
    def con(m):
        return 2 * m.x1 + m.x2 + 10.0 == m.EF(m.x1, m.x2)

    m.obj = Objective(expr=(m.x1 - 1)**2 + (m.x2 - 3)**2 + m.EF(m.x1, m.x2)**2)
    return m
Esempio n. 12
0
    def test_1(self):
        '''
        The simplest case that the black box has only two inputs and there is only one black block involved
        '''
        def blackbox(a,b):
            return sin(a-b)

        m = self.m
        bb = ExternalFunction(blackbox)
        m.eflist = [bb]
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + bb(m.x[0],m.x[1]) == 2*sqrt(2.0))
        pI = PyomoInterface(m, [bb], ConfigBlock())
        self.assertEqual(pI.lx,2)
        self.assertEqual(pI.ly,1)
        self.assertEqual(pI.lz,3)
        self.assertEqual(len(list(identify_variables(m.c1.body))),3)
        self.assertEqual(len(list(identify_variables(m.c2.body))),2)
Esempio n. 13
0
def delta_temperature_underwood_callback(b):
    """
    This is a callback for a temperaure difference expression to calculate
    :math:`\Delta T` in the heat exchanger model using log-mean temperature
    difference (LMTD) approximation given by Underwood (1970).  It can be
    supplied to "delta_temperature_callback" HeatExchanger configuration option.
    This uses a cube root function that works with negative numbers returning
    the real negative root. This should always evaluate successfully.
    """
    # external function that ruturns the real root, for the cuberoot of negitive
    # numbers, so it will return without error for positive and negitive dT.
    b.cbrt = ExternalFunction(library=functions_lib(), function="cbrt")
    dT1 = b.delta_temperature_in
    dT2 = b.delta_temperature_out
    @b.Expression(b.flowsheet().config.time)
    def delta_temperature(b, t):
        return ((b.cbrt(dT1[t]) + b.cbrt(dT2[t]))/2.0)**3
Esempio n. 14
0
    def test_assert_units_consistent_all_components(self):
        # test all scalar components consistent
        u = units
        m = self._create_model_and_vars()
        m.obj = Objective(expr=m.dx / m.t - m.vx)
        m.con = Constraint(expr=m.dx / m.t == m.vx)
        # vars already added
        m.exp = Expression(expr=m.dx / m.t - m.vx)
        m.suff = Suffix(direction=Suffix.LOCAL)
        # params already added
        # sets already added
        m.rs = RangeSet(5)
        m.disj1 = Disjunct()
        m.disj1.constraint = Constraint(expr=m.dx / m.t <= m.vx)
        m.disj2 = Disjunct()
        m.disj2.constraint = Constraint(expr=m.dx / m.t <= m.vx)
        m.disjn = Disjunction(expr=[m.disj1, m.disj2])
        # block tested as part of model
        m.extfn = ExternalFunction(python_callback_function,
                                   units=u.m / u.s,
                                   arg_units=[u.m, u.s])
        m.conext = Constraint(expr=m.extfn(m.dx, m.t) - m.vx == 0)
        m.cset = ContinuousSet(bounds=(0, 1))
        m.svar = Var(m.cset, units=u.m)
        m.dvar = DerivativeVar(sVar=m.svar, units=u.m / u.s)

        def prt1_rule(m):
            return {'avar': m.dx}

        def prt2_rule(m):
            return {'avar': m.dy}

        m.prt1 = Port(rule=prt1_rule)
        m.prt2 = Port(rule=prt2_rule)

        def arcrule(m):
            return dict(source=m.prt1, destination=m.prt2)

        m.arc = Arc(rule=arcrule)

        # complementarities do not work yet
        # The expression system removes the u.m since it is multiplied by zero.
        # We need to change the units_container to allow 0 when comparing units
        # m.compl = Complementarity(expr=complements(m.dx/m.t >= m.vx, m.dx == 0*u.m))

        assert_units_consistent(m)
Esempio n. 15
0
def create_model():
    m = ConcreteModel()
    m.name = 'Example 1: Eason'
    m.z = Var(range(3), domain=Reals, initialize=2.)
    m.x = Var(range(2), initialize=2.)
    m.x[1] = 1.0

    m.ext_fcn = ExternalFunction(ext_fcn, grad_ext_fcn)

    m.obj = Objective(
        expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
           + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6
    )

    m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 +
                      m.ext_fcn(m.x[0], m.x[1]) == 2 * sqrt(2.0))
    m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8 + sqrt(2.0))
    return m
Esempio n. 16
0
    def setUp(self):
        
        m = ConcreteModel()
        m.z = Var(range(3), domain=Reals, initialize=2.)
        m.x = Var(range(2), initialize=2.)
        m.x[1] = 1.0
        
        def blackbox(a,b):
            return sin(a-b)
        self.bb = ExternalFunction(blackbox)

        m.obj = Objective(
            expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
                + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6 # + m.bb(m.x[0],m.x[1])
            )
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + self.bb(m.x[0],m.x[1]) == 2*sqrt(2.0))
        m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8+sqrt(2.0))

        self.m = m.clone()
Esempio n. 17
0
    def test_2(self):
        '''
        The simplest case that the black box has only one inputs and there is only a formula
        '''
        def blackbox(a):
            return sin(a)

        m = self.m
        bb = ExternalFunction(blackbox)
        m.eflist = [bb]
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + bb(m.x[0]-m.x[1]) == 2*sqrt(2.0))
        pI = PyomoInterface(m, [bb], ConfigBlock())
        self.assertEqual(pI.lx,1)
        self.assertEqual(pI.ly,1)
        self.assertEqual(pI.lz,5)
        self.assertEqual(len(list(identify_variables(m.c1.body))),3)
        self.assertEqual(len(list(identify_variables(m.c2.body))),2)
        self.assertEqual(len(m.tR.conset),1)
        self.assertEqual(len(list(identify_variables(m.tR.conset[1].body))),3)
Esempio n. 18
0
    def test_external_expression_constant(self):
        DLL = find_GSL()
        if not DLL:
            self.skipTest("Could not find the amplgsl.dll library")

        m = ConcreteModel()
        m.y = Var(initialize=4, bounds=(0, None))
        m.hypot = ExternalFunction(library=DLL, function="gsl_hypot")
        m.o = Objective(expr=m.hypot(3, m.y))
        self.assertAlmostEqual(value(m.o), 5.0, 7)

        baseline_fname, test_fname = self._get_fnames()
        self._cleanup(test_fname)
        m.write(test_fname,
                format='nl',
                io_options={'symbolic_solver_labels': True})
        self.assertTrue(cmp(test_fname, baseline_fname),
                        msg="Files %s and %s differ" %
                        (test_fname, baseline_fname))
        self._cleanup(test_fname)
Esempio n. 19
0
    def test_external_function(self):
        m = ConcreteModel()
        m.t = ContinuousSet(bounds=(0, 10))

        def _fun(x):
            return x**2

        m.x_func = ExternalFunction(_fun)

        m.y = Var(m.t, initialize=3)
        m.dy = DerivativeVar(m.y, initialize=3)

        def _con(m, t):
            return m.dy[t] == m.x_func(m.y[t])

        m.con = Constraint(m.t, rule=_con)

        generate_finite_elements(m.t, 5)
        expand_components(m)

        self.assertEqual(len(m.y), 6)
        self.assertEqual(len(m.con), 6)
Esempio n. 20
0
def delta_temperature_chen_callback(b):
    r"""
    This is a callback for a temperature difference expression to calculate
    :math:`\Delta T` in the heat exchanger model using log-mean temperature
    difference (LMTD) approximation given by Chen (1987).  It can be
    supplied to "delta_temperature_callback" HeatExchanger configuration option.
    This uses a cube root function that works with negative numbers returning
    the real negative root. This should always evaluate successfully.
    """
    dT1 = b.delta_temperature_in
    dT2 = b.delta_temperature_out
    temp_units = pyunits.get_units(dT1)

    # external function that ruturns the real root, for the cuberoot of negitive
    # numbers, so it will return without error for positive and negitive dT.
    b.cbrt = ExternalFunction(library=functions_lib(),
                              function="cbrt",
                              arg_units=[temp_units**3])

    @b.Expression(b.flowsheet().time)
    def delta_temperature(b, t):
        return b.cbrt(dT1[t] * dT2[t] * 0.5 * (dT1[t] + dT2[t])) * temp_units
Esempio n. 21
0
    def test_execute_TRF(self):
        m = ConcreteModel()
        m.z = Var(range(3), domain=Reals, initialize=2.)
        m.x = Var(range(2), initialize=2.)
        m.x[1] = 1.0

        def blackbox(a,b):
            return sin(a-b)
        bb = ExternalFunction(blackbox)

        m.obj = Objective(
            expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
            + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6 # + m.bb(m.x[0],m.x[1])
        )
        m.c1 = Constraint(
            expr=m.x[0] * m.z[0]**2 + bb(m.x[0],m.x[1]) == 2*sqrt(2.0))
        m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8+sqrt(2.0))

        SolverFactory('trustregion').solve(m, [bb])

        self.assertAlmostEqual(value(m.obj), 0.277044789315, places=4)
        self.assertAlmostEqual(value(m.x[0]), 1.32193855369, places=4)
        self.assertAlmostEqual(value(m.x[1]), 0.628744699822, places=4)
Esempio n. 22
0
    def setUp(self):
        # Borrowed this test model from the trust region tests
        m = ConcreteModel(name="tm")
        m.z = Var(range(3), domain=Reals, initialize=2.)
        m.x = Var(range(2), initialize=2.)
        m.x[1] = 1.0

        m.b1 = Block()
        m.b1.e1 = Expression(expr=m.x[0] + m.x[1])

        def blackbox(a, b):
            return sin(a - b)

        self.bb = ExternalFunction(blackbox)

        m.obj = Objective(
            expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
                + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6 # + m.bb(m.x[0],m.x[1])
            )
        m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 +
                          self.bb(m.x[0], m.x[1]) == 2 * sqrt(2.0))
        m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8 + sqrt(2.0))

        self.m = m.clone()
Esempio n. 23
0
#  ___________________________________________________________________________

from pyomo.environ import ConcreteModel, Var, Reals, ExternalFunction, sin, sqrt, Constraint, Objective
from pyomo.opt import SolverFactory

m = ConcreteModel()
m.z = Var(range(3), domain=Reals, initialize=2.)
m.x = Var(range(2), initialize=2.)
m.x[1] = 1.0


def blackbox(a, b):
    return sin(a - b)


bb = ExternalFunction(blackbox)

m.obj = Objective(
   expr=(m.z[0]-1.0)**2 + (m.z[0]-m.z[1])**2 + (m.z[2]-1.0)**2 \
       + (m.x[0]-1.0)**4 + (m.x[1]-1.0)**6 # + m.bb(m.x[0],m.x[1])
)
m.c1 = Constraint(expr=m.x[0] * m.z[0]**2 + bb(m.x[0], m.x[1]) == 2 *
                  sqrt(2.0))
m.c2 = Constraint(expr=m.z[2]**4 * m.z[1]**2 + m.z[1] == 8 + sqrt(2.0))

m.pprint()

optTRF = SolverFactory('trustregion')
optTRF.solve(m, [bb])

m.display()
Esempio n. 24
0
    def build(self):
        """
        Building model

        Args:
            None
        Returns:
            None
        """
        # Call UnitModel.build to setup dynamics
        super().build()
        config = self.config
        # Add variables
        self.overall_heat_transfer_coefficient = Var(
            self.flowsheet().config.time,
            domain=PositiveReals,
            initialize=100,
            doc="Overall heat transfer coefficient")
        self.overall_heat_transfer_coefficient.latex_symbol = "U"
        self.area = Var(domain=PositiveReals,
                        initialize=1000,
                        doc="Heat exchange area")
        self.area.latex_symbol = "A"
        if config.flow_pattern == HeatExchangerFlowPattern.crossflow:
            self.crossflow_factor = Var(
                self.flowsheet().config.time,
                initialize=1,
                doc="Factor to adjust coutercurrent flow heat transfer "
                "calculation for cross flow.")

        if config.delta_temperature_rule == delta_temperature_underwood2_rule:
            # Define a cube root function that return the real negative root
            # for the cube root of a negative number.
            self.cbrt = ExternalFunction(library=functions_lib(),
                                         function="cbrt")

        # Add Control Volumes
        _make_heater_control_volume(self,
                                    "side_1",
                                    config.side_1,
                                    dynamic=config.dynamic,
                                    has_holdup=config.has_holdup)
        _make_heater_control_volume(self,
                                    "side_2",
                                    config.side_2,
                                    dynamic=config.dynamic,
                                    has_holdup=config.has_holdup)
        # Add Ports
        self.add_inlet_port(name="inlet_1", block=self.side_1)
        self.add_inlet_port(name="inlet_2", block=self.side_2)
        self.add_outlet_port(name="outlet_1", block=self.side_1)
        self.add_outlet_port(name="outlet_2", block=self.side_2)
        # Add convienient references to heat duty.
        add_object_reference(self, "heat_duty", self.side_2.heat)
        self.side_1.heat.latex_symbol = "Q_1"
        self.side_2.heat.latex_symbol = "Q_2"

        @self.Expression(self.flowsheet().config.time,
                         doc="Temperature difference at the side 1 inlet end")
        def delta_temperature_in(b, t):
            if b.config.flow_pattern == \
                    HeatExchangerFlowPattern.countercurrent:
                return b.side_1.properties_in[t].temperature -\
                       b.side_2.properties_out[t].temperature
            elif b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return b.side_1.properties_in[t].temperature -\
                       b.side_2.properties_in[t].temperature
            elif b.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
                return b.side_1.properties_in[t].temperature -\
                       b.side_2.properties_out[t].temperature
            else:
                raise ConfigurationError(
                    "Flow pattern {} not supported".format(
                        b.config.flow_pattern))

        @self.Expression(self.flowsheet().config.time,
                         doc="Temperature difference at the side 1 outlet end")
        def delta_temperature_out(b, t):
            if b.config.flow_pattern == \
                    HeatExchangerFlowPattern.countercurrent:
                return b.side_1.properties_out[t].temperature -\
                       b.side_2.properties_in[t].temperature
            elif b.config.flow_pattern == HeatExchangerFlowPattern.cocurrent:
                return b.side_1.properties_out[t].temperature -\
                       b.side_2.properties_out[t].temperature
            elif b.config.flow_pattern == HeatExchangerFlowPattern.crossflow:
                return b.side_1.properties_out[t].temperature -\
                       b.side_2.properties_in[t].temperature

        # Add a unit level energy balance
        def unit_heat_balance_rule(b, t):
            return 0 == self.side_1.heat[t] + self.side_2.heat[t]

        self.unit_heat_balance = Constraint(self.flowsheet().config.time,
                                            rule=unit_heat_balance_rule)
        # Add heat transfer equation
        self.delta_temperature = Expression(
            self.flowsheet().config.time,
            rule=config.delta_temperature_rule,
            doc="Temperature difference driving force for heat transfer")
        self.delta_temperature.latex_symbol = "\\Delta T"

        if config.flow_pattern == HeatExchangerFlowPattern.crossflow:
            self.heat_transfer_equation = Constraint(
                self.flowsheet().config.time,
                rule=_cross_flow_heat_transfer_rule)
        else:
            self.heat_transfer_equation = Constraint(
                self.flowsheet().config.time, rule=_heat_transfer_rule)
Esempio n. 25
0
    def test_as_quantity_expression(self):
        _pint = units._pint_registry
        Quantity = _pint.Quantity
        m = ConcreteModel()
        m.x = Var(initialize=1)
        m.y = Var(initialize=2, units=units.g)
        m.p = Param(initialize=3)
        m.q = Param(initialize=4, units=1 / units.s)

        q = as_quantity(m.x * m.p)
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 3 * _pint.dimensionless)

        q = as_quantity(m.x * m.q)
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 4 / _pint.s)

        q = as_quantity(m.y * m.p)
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 6 * _pint.g)

        q = as_quantity(m.y * m.q)
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 8 * _pint.g / _pint.s)

        q = as_quantity(m.y <= 2 * m.y)
        self.assertIs(q.__class__, bool)
        self.assertEqual(q, True)

        q = as_quantity(m.y >= 2 * m.y)
        self.assertIs(q.__class__, bool)
        self.assertEqual(q, False)

        q = as_quantity(EXPR.Expr_if(IF=m.y <= 2 * m.y, THEN=m.x, ELSE=m.p))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 1 * _pint.dimensionless)

        q = as_quantity(EXPR.Expr_if(IF=m.y >= 2 * m.y, THEN=m.x, ELSE=m.p))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 3 * _pint.dimensionless)

        # NOTE: The following two tests are not unit consistent (but can
        # be evaluated)

        q = as_quantity(EXPR.Expr_if(IF=m.x <= 2 * m.x, THEN=m.y, ELSE=m.q))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 2 * _pint.g)

        q = as_quantity(EXPR.Expr_if(IF=m.x >= 2 * m.x, THEN=m.y, ELSE=m.q))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q, 4 / _pint.s)

        # Note: check the units explicitly, as
        #   Quantity(x, radian) == Quantity(x, dimensionless)
        q = as_quantity(acos(m.x))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q.units, _pint.radian)
        self.assertEqual(q, 0 * _pint.radian)

        q = as_quantity(cos(m.x * math.pi))
        self.assertIs(q.__class__, Quantity)
        self.assertEqual(q.units, _pint.dimensionless)
        self.assertAlmostEqual(q, -1 * _pint.dimensionless)

        def MyAdder(x, y):
            return x + y

        m.EF = ExternalFunction(MyAdder, units=units.kg)
        ef = m.EF(m.x, m.y)
        q = as_quantity(ef)
        self.assertIs(q.__class__, Quantity)
        self.assertAlmostEqual(q, 3 * _pint.kg)
Esempio n. 26
0
    def test_get_check_units_on_all_expressions(self):
        # this method is going to test all the expression types that should work
        # to be defensive, we will also test that we actually have the expected expression type
        # therefore, if the expression system changes and we get a different expression type,
        # we will know we need to change these tests

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # test ExternalFunctionExpression, NPV_ExternalFunctionExpression
        model.ef3 = ExternalFunction(python_callback_function, units=uc.kg, arg_units=[uc.kg, uc.m])
        self._get_check_units_fail(model.ef3(model.x, model.y), uc, EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(1.0, 2.0), uc, EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.x*kg, model.y), uc, EXPR.ExternalFunctionExpression, UnitsError)
        self._get_check_units_fail(model.ef3(2.0*kg, 1.0), uc, EXPR.NPV_ExternalFunctionExpression, UnitsError)
        self._get_check_units_ok(model.ef3(2.0*kg, 1.0*uc.m), uc, 'kg', EXPR.NPV_ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.x*kg, model.y*m), uc, 'kg', EXPR.ExternalFunctionExpression)
        self._get_check_units_ok(model.ef3(model.xkg, model.ym), uc, 'kg', EXPR.ExternalFunctionExpression)
        self._get_check_units_fail(model.ef3(model.ym, model.xkg), uc, EXPR.ExternalFunctionExpression, InconsistentUnitsError)
Esempio n. 27
0
    def common(b, pobj):
        # TODO: determine if Henry's Law applies to Cubic EoS systems
        # For now, raise an exception if found
        # Follow on questions:
        # If Henry's law is used for a component, how does that effect
        # calculating A, B and phi?
        for j in b.component_list:
            cobj = b.params.get_component(j)
            if (cobj.config.henry_component is not None
                    and pobj.local_name in cobj.config.henry_component):
                raise PropertyNotSupportedError(
                    "{} Cubic equations of state do not support Henry's "
                    "components [{}, {}].".format(b.name, pobj.local_name, j))

        ctype = pobj._cubic_type
        cname = pobj.config.equation_of_state_options["type"].name
        mixing_rule_a = pobj._mixing_rule_a
        mixing_rule_b = pobj._mixing_rule_b

        if hasattr(b, cname + "_fw"):
            # Common components already constructed by previous phase
            return

        # Create expressions for coefficients
        def rule_fw(m, j):
            func_fw = getattr(m.params, cname + "_func_fw")
            cobj = m.params.get_component(j)
            return func_fw(cobj)

        b.add_component(
            cname + '_fw',
            Expression(b.component_list, rule=rule_fw, doc='EoS S factor'))

        def rule_a_crit(m, j):
            cobj = m.params.get_component(j)
            return (EoS_param[ctype]['omegaA'] *
                    ((Cubic.gas_constant(b) * cobj.temperature_crit)**2 /
                     cobj.pressure_crit))

        b.add_component(
            cname + '_a_crit',
            Expression(b.component_list,
                       rule=rule_a_crit,
                       doc='Component a coefficient at T_crit'))

        def rule_a(m, j):
            cobj = m.params.get_component(j)
            fw = getattr(m, cname + "_fw")[j]
            ac = getattr(m, cname + '_a_crit')[j]
            func_alpha = getattr(m.params, cname + "_func_alpha")

            return ac * func_alpha(m.temperature, fw, cobj)

        b.add_component(
            cname + '_a',
            Expression(b.component_list,
                       rule=rule_a,
                       doc='Component a coefficient'))

        def rule_da_dT(m, j):
            cobj = m.params.get_component(j)
            fw = getattr(m, cname + "_fw")[j]
            ac = getattr(m, cname + '_a_crit')[j]
            func_dalpha_dT = getattr(m.params, cname + "_func_dalpha_dT")

            return ac * func_dalpha_dT(m.temperature, fw, cobj)

        b.add_component(
            cname + '_da_dT',
            Expression(b.component_list,
                       rule=rule_da_dT,
                       doc='Temperature derivative of component a'))

        def rule_d2a_dT2(m, j):
            cobj = m.params.get_component(j)
            fw = getattr(m, cname + "_fw")[j]
            ac = getattr(m, cname + '_a_crit')[j]
            func_d2alpha_dT2 = getattr(m.params, cname + "_func_d2alpha_dT2")

            return ac * func_d2alpha_dT2(m.temperature, fw, cobj)

        b.add_component(
            cname + '_d2a_dT2',
            Expression(b.component_list,
                       rule=rule_d2a_dT2,
                       doc='Second temperature derivative'
                       'of component a'))

        def func_b(m, j):
            cobj = m.params.get_component(j)
            return (EoS_param[ctype]['coeff_b'] * Cubic.gas_constant(b) *
                    cobj.temperature_crit / cobj.pressure_crit)

        b.add_component(
            cname + '_b',
            Expression(b.component_list,
                       rule=func_b,
                       doc='Component b coefficient'))

        if mixing_rule_a == MixingRuleA.default:

            def rule_am(m, p):
                a = getattr(m, cname + "_a")
                return rule_am_default(m, cname, a, p)

            b.add_component(cname + '_am',
                            Expression(b.phase_list, rule=rule_am))

            def rule_daij_dT(m, i, j):
                a = getattr(m, cname + "_a")
                da_dT = getattr(m, cname + "_da_dT")
                k = getattr(m.params, cname + "_kappa")

                # Include temperature derivative of k for future extension
                dk_ij_dT = 0

                return sqrt(
                    a[i] * a[j]) * (-dk_ij_dT + (1 - k[i, j]) / 2 *
                                    (da_dT[i] / a[i] + da_dT[j] / a[j]))

            b.add_component(
                cname + '_daij_dT',
                Expression(b.component_list,
                           b.component_list,
                           rule=rule_daij_dT))

            def rule_dam_dT(m, p):
                daij_dT = getattr(m, cname + "_daij_dT")
                return sum(
                    sum(m.mole_frac_phase_comp[p, i] *
                        m.mole_frac_phase_comp[p, j] * daij_dT[i, j]
                        for j in m.components_in_phase(p))
                    for i in m.components_in_phase(p))

            b.add_component(cname + "_dam_dT",
                            Expression(b.phase_list, rule=rule_dam_dT))

            def rule_d2am_dT2(m, p):
                k = getattr(m.params, cname + "_kappa")
                a = getattr(m, cname + "_a")
                da_dT = getattr(m, cname + "_da_dT")
                d2a_dT2 = getattr(m, cname + "_d2a_dT2")
                # Placeholders for if temperature dependent k is needed
                dk_dT = 0
                d2k_dT2 = 0

                # Initialize loop variable
                d2am_dT2 = 0

                for i in m.components_in_phase(p):
                    for j in m.components_in_phase(p):
                        d2aij_dT2 = (
                            sqrt(a[i] * a[j]) *
                            (-d2k_dT2 - dk_dT *
                             (da_dT[i] / a[i] + da_dT[j] / a[j]) +
                             (1 - k[i, j]) / 2 *
                             (d2a_dT2[i] / a[i] + d2a_dT2[j] / a[j] - 1 / 2 *
                              (da_dT[i] / a[i] - da_dT[j] / a[j])**2)))
                        d2am_dT2 += (m.mole_frac_phase_comp[p, i] *
                                     m.mole_frac_phase_comp[p, j] * d2aij_dT2)
                return d2am_dT2

            b.add_component(cname + "_d2am_dT2",
                            Expression(b.phase_list, rule=rule_d2am_dT2))

            def rule_delta(m, p, i):
                # See pg. 145 in Properties of Gases and Liquids
                a = getattr(m, cname + "_a")
                am = getattr(m, cname + "_am")
                kappa = getattr(m.params, cname + "_kappa")
                return (2 * sqrt(a[i]) / am[p] *
                        sum(m.mole_frac_phase_comp[p, j] * sqrt(a[j]) *
                            (1 - kappa[i, j])
                            for j in b.components_in_phase(p)))

            b.add_component(cname + "_delta",
                            Expression(b.phase_component_set, rule=rule_delta))

        else:
            raise ConfigurationError(
                "{} Unrecognized option for Equation of State "
                "mixing_rule_a: {}. Must be an instance of MixingRuleA "
                "Enum.".format(b.name, mixing_rule_a))

        if mixing_rule_b == MixingRuleB.default:

            def rule_bm(m, p):
                b = getattr(m, cname + "_b")
                return rule_bm_default(m, b, p)

            b.add_component(cname + '_bm',
                            Expression(b.phase_list, rule=rule_bm))
        else:
            raise ConfigurationError(
                "{} Unrecognized option for Equation of State "
                "mixing_rule_a: {}. Must be an instance of MixingRuleB "
                "Enum.".format(b.name, mixing_rule_b))

        def rule_A(m, p):
            am = getattr(m, cname + "_am")
            return (am[p] * m.pressure /
                    (Cubic.gas_constant(b) * m.temperature)**2)

        b.add_component(cname + '_A', Expression(b.phase_list, rule=rule_A))

        def rule_B(m, p):
            bm = getattr(m, cname + "_bm")
            return (bm[p] * m.pressure /
                    (Cubic.gas_constant(b) * m.temperature))

        b.add_component(cname + '_B', Expression(b.phase_list, rule=rule_B))

        # Add components at equilibrium state if required
        if (b.params.config.phases_in_equilibrium is not None
                and (not b.config.defined_state or b.always_flash)):

            def func_a_eq(m, p1, p2, j):
                cobj = m.params.get_component(j)
                fw = getattr(m, cname + "_fw")[j]
                ac = getattr(m, cname + '_a_crit')[j]
                func_alpha = getattr(m.params, cname + "_func_alpha")

                return ac * func_alpha(m._teq[p1, p2], fw, cobj)

            b.add_component(
                '_' + cname + '_a_eq',
                Expression(b.params._pe_pairs,
                           b.component_list,
                           rule=func_a_eq,
                           doc='Component a coefficient at Teq'))

            def rule_am_eq(m, p1, p2, p3):
                try:
                    rule = m.params.get_phase(
                        p3).config.equation_of_state_options["mixing_rule_a"]
                except (KeyError, TypeError):
                    rule = MixingRuleA.default

                a = getattr(m, "_" + cname + "_a_eq")
                if rule == MixingRuleA.default:
                    return rule_am_default(m, cname, a, p3, (p1, p2))
                else:
                    raise ConfigurationError(
                        "{} Unrecognized option for Equation of State "
                        "mixing_rule_a: {}. Must be an instance of MixingRuleA "
                        "Enum.".format(m.name, rule))

            b.add_component(
                '_' + cname + '_am_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_am_eq))

            def rule_A_eq(m, p1, p2, p3):
                am_eq = getattr(m, "_" + cname + "_am_eq")
                return (am_eq[p1, p2, p3] * m.pressure /
                        (Cubic.gas_constant(b) * m._teq[p1, p2])**2)

            b.add_component(
                '_' + cname + '_A_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_A_eq))

            def rule_B_eq(m, p1, p2, p3):
                bm = getattr(m, cname + "_bm")
                return (bm[p3] * m.pressure /
                        (Cubic.gas_constant(b) * m._teq[p1, p2]))

            b.add_component(
                '_' + cname + '_B_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_B_eq))

            def rule_delta_eq(m, p1, p2, p3, i):
                # See pg. 145 in Properties of Gases and Liquids
                a = getattr(m, "_" + cname + "_a_eq")
                am = getattr(m, "_" + cname + "_am_eq")
                kappa = getattr(m.params, cname + "_kappa")
                return (
                    2 * sqrt(a[p1, p2, i]) / am[p1, p2, p3] *
                    sum(m.mole_frac_phase_comp[p3, j] * sqrt(a[p1, p2, j]) *
                        (1 - kappa[i, j]) for j in m.components_in_phase(p3)))

            b.add_component(
                "_" + cname + "_delta_eq",
                Expression(b.params._pe_pairs,
                           b.phase_component_set,
                           rule=rule_delta_eq))

        # Set up external function calls
        b.add_component("_" + cname + "_ext_func_param",
                        Param(default=ctype.value))
        b.add_component("_" + cname + "_proc_Z_liq",
                        ExternalFunction(library=_so, function="ceos_z_liq"))
        b.add_component("_" + cname + "_proc_Z_vap",
                        ExternalFunction(library=_so, function="ceos_z_vap"))
Esempio n. 28
0
Al = 0.0419062
Bl = 0.0262770
Av = 0.1180005
Bv = 0.0262769
Zl = 0.9870125
Zv = 0.9067390

Al_eq = 0.8325554
Bl_eq = 0.0788309
Av_eq = 1.9805792
Bv_eq = 0.0788309


# Set path to root finder .so file
_so = os.path.join(bin_directory, "cubic_roots.so")
f_Zl = ExternalFunction(library=_so, function="ceos_z_liq")
f_Zv = ExternalFunction(library=_so, function="ceos_z_vap")


@pytest.mark.unit
def test_common(m):
    # Test cubic components
    assert isinstance(m.props[1].PR_fw, Expression)
    assert len(m.props[1].PR_fw) == len(m.params.component_list)
    for i in m.params.component_list:
        omega = m.params.get_component(i).omega
        assert value(m.props[1].PR_fw[i]) == value(
            0.37464 + 1.54226*omega - 0.26992*omega**2)

    assert isinstance(m.props[1].PR_a, Expression)
    assert len(m.props[1].PR_a) == len(m.params.component_list)
Esempio n. 29
0
    def common(b, pobj):
        ctype = pobj._cubic_type
        cname = pobj.config.equation_of_state_options["type"].name

        if hasattr(b, cname + "_fw"):
            # Common components already constructed by previous phase
            return

        # Create expressions for coefficients
        def func_fw(m, j):
            cobj = m.params.get_component(j)
            if ctype == CubicType.PR:
                return 0.37464 + 1.54226*cobj.omega - \
                       0.26992*cobj.omega**2
            elif ctype == CubicType.SRK:
                return 0.48 + 1.574*cobj.omega - \
                       0.176*cobj.omega**2
            else:
                raise BurntToast(
                    "{} received unrecognized cubic type. This should "
                    "never happen, so please contact the IDAES developers "
                    "with this bug.".format(b.name))

        b.add_component(
            cname + '_fw',
            Expression(b.component_list, rule=func_fw, doc='EoS S factor'))

        def func_a(m, j):
            cobj = m.params.get_component(j)
            fw = getattr(m, cname + "_fw")
            return (EoS_param[ctype]['omegaA'] *
                    ((Cubic.gas_constant(b) * cobj.temperature_crit)**2 /
                     cobj.pressure_crit) *
                    ((1 + fw[j] *
                      (1 - sqrt(m.temperature / cobj.temperature_crit)))**2))

        b.add_component(
            cname + '_a',
            Expression(b.component_list,
                       rule=func_a,
                       doc='Component a coefficient'))

        def func_b(m, j):
            cobj = m.params.get_component(j)
            return (EoS_param[ctype]['coeff_b'] * Cubic.gas_constant(b) *
                    cobj.temperature_crit / cobj.pressure_crit)

        b.add_component(
            cname + '_b',
            Expression(b.component_list,
                       rule=func_b,
                       doc='Component b coefficient'))

        def rule_am(m, p):
            try:
                rule = m.params.get_phase(
                    p).config.equation_of_state_options["mixing_rule_a"]
            except KeyError:
                rule = MixingRuleA.default

            a = getattr(m, cname + "_a")
            if rule == MixingRuleA.default:
                return rule_am_default(m, cname, a, p)
            else:
                raise ConfigurationError(
                    "{} Unrecognized option for Equation of State "
                    "mixing_rule_a: {}. Must be an instance of MixingRuleA "
                    "Enum.".format(m.name, rule))

        b.add_component(cname + '_am', Expression(b.phase_list, rule=rule_am))

        def rule_bm(m, p):
            try:
                rule = m.params.get_phase(
                    p).config.equation_of_state_options["mixing_rule_b"]
            except KeyError:
                rule = MixingRuleB.default

            b = getattr(m, cname + "_b")
            if rule == MixingRuleB.default:
                return rule_bm_default(m, b, p)
            else:
                raise ConfigurationError(
                    "{} Unrecognized option for Equation of State "
                    "mixing_rule_a: {}. Must be an instance of MixingRuleB "
                    "Enum.".format(m.name, rule))

        b.add_component(cname + '_bm', Expression(b.phase_list, rule=rule_bm))

        def rule_A(m, p):
            am = getattr(m, cname + "_am")
            return (am[p] * m.pressure /
                    (Cubic.gas_constant(b) * m.temperature)**2)

        b.add_component(cname + '_A', Expression(b.phase_list, rule=rule_A))

        def rule_B(m, p):
            bm = getattr(m, cname + "_bm")
            return (bm[p] * m.pressure /
                    (Cubic.gas_constant(b) * m.temperature))

        b.add_component(cname + '_B', Expression(b.phase_list, rule=rule_B))

        def rule_delta(m, p, i):
            # See pg. 145 in Properties of Gases and Liquids
            a = getattr(m, cname + "_a")
            am = getattr(m, cname + "_am")
            kappa = getattr(m.params, cname + "_kappa")
            return (2 * sqrt(a[i]) / am[p] *
                    sum(m.mole_frac_phase_comp[p, j] * sqrt(a[j]) *
                        (1 - kappa[i, j]) for j in b.components_in_phase(p)))

        b.add_component(cname + "_delta",
                        Expression(b.phase_component_set, rule=rule_delta))

        def rule_dadT(m, p):
            # See pg. 102 in Properties of Gases and Liquids
            a = getattr(m, cname + "_a")
            fw = getattr(m, cname + "_fw")
            kappa = getattr(m.params, cname + "_kappa")
            return -(
                (Cubic.gas_constant(b) / 2) *
                sqrt(EoS_param[ctype]['omegaA']) * sum(
                    sum(m.mole_frac_phase_comp[p, i] *
                        m.mole_frac_phase_comp[p, j] * (1 - kappa[i, j]) *
                        (fw[j] * sqrt(
                            a[i] * m.params.get_component(j).temperature_crit /
                            m.params.get_component(j).pressure_crit) + fw[i] *
                         sqrt(a[j] * m.params.get_component(i).temperature_crit
                              / m.params.get_component(i).pressure_crit))
                        for j in m.components_in_phase(p))
                    for i in m.components_in_phase(p)) / sqrt(m.temperature))

        b.add_component(cname + "_dadT",
                        Expression(b.phase_list, rule=rule_dadT))

        # Add components at equilibrium state if required
        if (b.params.config.phases_in_equilibrium is not None
                and (not b.config.defined_state or b.always_flash)):

            def func_a_eq(m, p1, p2, j):
                cobj = m.params.get_component(j)
                fw = getattr(m, cname + "_fw")
                return (
                    EoS_param[ctype]['omegaA'] *
                    ((Cubic.gas_constant(b) * cobj.temperature_crit)**2 /
                     cobj.pressure_crit) *
                    ((1 + fw[j] *
                      (1 - sqrt(m._teq[p1, p2] / cobj.temperature_crit)))**2))

            b.add_component(
                '_' + cname + '_a_eq',
                Expression(b.params._pe_pairs,
                           b.component_list,
                           rule=func_a_eq,
                           doc='Component a coefficient at Teq'))

            def rule_am_eq(m, p1, p2, p3):
                try:
                    rule = m.params.get_phase(
                        p3).config.equation_of_state_options["mixing_rule_a"]
                except KeyError:
                    rule = MixingRuleA.default

                a = getattr(m, "_" + cname + "_a_eq")
                if rule == MixingRuleA.default:
                    return rule_am_default(m, cname, a, p3, (p1, p2))
                else:
                    raise ConfigurationError(
                        "{} Unrecognized option for Equation of State "
                        "mixing_rule_a: {}. Must be an instance of MixingRuleA "
                        "Enum.".format(m.name, rule))

            b.add_component(
                '_' + cname + '_am_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_am_eq))

            def rule_A_eq(m, p1, p2, p3):
                am_eq = getattr(m, "_" + cname + "_am_eq")
                return (am_eq[p1, p2, p3] * m.pressure /
                        (Cubic.gas_constant(b) * m._teq[p1, p2])**2)

            b.add_component(
                '_' + cname + '_A_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_A_eq))

            def rule_B_eq(m, p1, p2, p3):
                bm = getattr(m, cname + "_bm")
                return (bm[p3] * m.pressure /
                        (Cubic.gas_constant(b) * m._teq[p1, p2]))

            b.add_component(
                '_' + cname + '_B_eq',
                Expression(b.params._pe_pairs, b.phase_list, rule=rule_B_eq))

            def rule_delta_eq(m, p1, p2, p3, i):
                # See pg. 145 in Properties of Gases and Liquids
                a = getattr(m, "_" + cname + "_a_eq")
                am = getattr(m, "_" + cname + "_am_eq")
                kappa = getattr(m.params, cname + "_kappa")
                return (
                    2 * sqrt(a[p1, p2, i]) / am[p1, p2, p3] *
                    sum(m.mole_frac_phase_comp[p3, j] * sqrt(a[p1, p2, j]) *
                        (1 - kappa[i, j]) for j in m.components_in_phase(p3)))

            b.add_component(
                "_" + cname + "_delta_eq",
                Expression(b.params._pe_pairs,
                           b.phase_component_set,
                           rule=rule_delta_eq))

        # Set up external function calls
        b.add_component("_" + cname + "_ext_func_param",
                        Param(default=ctype.value))
        b.add_component("_" + cname + "_proc_Z_liq",
                        ExternalFunction(library=_so, function="ceos_z_liq"))
        b.add_component("_" + cname + "_proc_Z_vap",
                        ExternalFunction(library=_so, function="ceos_z_vap"))