예제 #1
0
    def test_simple_substitute_param(self):
        def diffeq(m, t, i):
            return m.dxdt[t, i] == t * m.x[t, i - 1] ** 2 + m.y ** 2 + m.x[t, i + 1] + m.x[t, i - 1]

        m = self.m
        t = IndexTemplate(m.TIME)
        e = diffeq(m, t, 2)

        self.assertTrue(isinstance(e, EXPR._ExpressionBase))

        _map = {}
        E = substitute_template_expression(e, substitute_getitem_with_param, _map)
        self.assertIsNot(e, E)

        self.assertEqual(len(_map), 3)

        idx1 = _GetItemIndexer(m.x[t, 1])
        self.assertIs(idx1._base, m.x)
        self.assertEqual(len(idx1._args), 2)
        self.assertIs(idx1._args[0], t)
        self.assertEqual(idx1._args[1], 1)
        self.assertIn(idx1, _map)

        idx2 = _GetItemIndexer(m.dxdt[t, 2])
        self.assertIs(idx2._base, m.dxdt)
        self.assertEqual(len(idx2._args), 2)
        self.assertIs(idx2._args[0], t)
        self.assertEqual(idx2._args[1], 2)
        self.assertIn(idx2, _map)

        idx3 = _GetItemIndexer(m.x[t, 3])
        self.assertIs(idx3._base, m.x)
        self.assertEqual(len(idx3._args), 2)
        self.assertIs(idx3._args[0], t)
        self.assertEqual(idx3._args[1], 3)
        self.assertIn(idx3, _map)

        self.assertFalse(idx1 == idx2)
        self.assertFalse(idx1 == idx3)
        self.assertFalse(idx2 == idx3)

        idx4 = _GetItemIndexer(m.x[t, 2])
        self.assertNotIn(idx4, _map)

        t.set_value(5)
        self.assertEqual((e._args[0](), e._args[1]()), (10, 136))

        self.assertEqual(str(E), "dxdt[{TIME},2]  ==  {TIME} * x[{TIME},1]**2.0 + y**2.0 + x[{TIME},3] + x[{TIME},1]")

        _map[idx1].set_value(value(m.x[value(t), 1]))
        _map[idx2].set_value(value(m.dxdt[value(t), 2]))
        _map[idx3].set_value(value(m.x[value(t), 3]))
        self.assertEqual((E._args[0](), E._args[1]()), (10, 136))

        _map[idx1].set_value(12)
        _map[idx2].set_value(34)
        self.assertEqual((E._args[0](), E._args[1]()), (34, 738))
예제 #2
0
    def test_substitute_casadi_intrinsic1(self):

        m = self.m
        m.y = Var()
        t = IndexTemplate(m.t)

        e = m.v[t]
        templatemap = {}
        e2 = substitute_template_expression(
            e, substitute_getitem_with_casadi_sym, templatemap)
        e3 = substitute_intrinsic_function(
            e2, substitute_intrinsic_function_with_casadi)
        self.assertIs(type(e3), casadi.SX)

        m.del_component('y')
예제 #3
0
    def test_substitute_casadi_intrinsic3(self):

        m = self.m
        m.y = Var()
        t = IndexTemplate(m.t)

        e = sin(m.dv[t] + m.v[t]) + log(m.v[t] * m.y + m.dv[t]**2)
        templatemap = {}
        e2 = substitute_template_expression(
            e, substitute_getitem_with_casadi_sym, templatemap)
        e3 = substitute_intrinsic_function(
            e2, substitute_intrinsic_function_with_casadi)
        self.assertIs(e3._args[0]._operator, casadi.sin)
        self.assertIs(e3._args[1]._operator, casadi.log)

        m.del_component('y')
예제 #4
0
    def test_simple_substitute_index(self):
        def diffeq(m, t, i):
            return m.dxdt[t, i] == t * m.x[t, i]**2 + m.y**2

        m = self.m
        t = IndexTemplate(m.TIME)
        e = diffeq(m, t, 2)
        t.set_value(5)

        self.assertTrue(isinstance(e, EXPR._ExpressionBase))
        self.assertEqual((e._args[0](), e._args[1]()), (10, 126))

        E = substitute_template_expression(e, substitute_template_with_value)
        self.assertIsNot(e, E)

        self.assertEqual(str(E), 'dxdt[5,2]  ==  5.0 * x[5,2]**2.0 + y**2.0')
예제 #5
0
    def test_simple_substitute_index(self):
        def diffeq(m, t, i):
            return m.dxdt[t, i] == t * m.x[t, i] ** 2 + m.y ** 2

        m = self.m
        t = IndexTemplate(m.TIME)
        e = diffeq(m, t, 2)
        t.set_value(5)

        self.assertTrue(isinstance(e, EXPR._ExpressionBase))
        self.assertEqual((e._args[0](), e._args[1]()), (10, 126))

        E = substitute_template_expression(e, substitute_template_with_value)
        self.assertIsNot(e, E)

        self.assertEqual(str(E), "dxdt[5,2]  ==  5.0 * x[5,2]**2.0 + y**2.0")
예제 #6
0
    def test_substitute_casadi_sym(self):

        m = self.m
        m.y = Var()
        t = IndexTemplate(m.t)

        e = m.dv[t] + m.v[t] + m.y + t
        templatemap = {}
        e2 = substitute_template_expression(
            e, substitute_getitem_with_casadi_sym, templatemap)
        self.assertEqual(len(templatemap), 2)
        self.assertIs(type(e2._args[0]), casadi.SX)
        self.assertIs(type(e2._args[1]), casadi.SX)
        self.assertIsNot(type(e2._args[2]), casadi.SX)
        self.assertIs(type(e2._args[3]), IndexTemplate)

        m.del_component('y')
예제 #7
0
    def test_substitute_casadi_intrinsic4(self):

        m = self.m
        m.y = Var()
        t = IndexTemplate(m.t)

        e = m.v[t] * sin(m.dv[t] + m.v[t]) * t
        templatemap = {}
        e2 = substitute_template_expression(
            e, substitute_getitem_with_casadi_sym, templatemap)
        e3 = substitute_intrinsic_function(
            e2, substitute_intrinsic_function_with_casadi)
        self.assertIs(type(e3._numerator[0]), casadi.SX)
        self.assertIs(e3._numerator[1]._operator, casadi.sin)
        self.assertIs(type(e3._numerator[2]), IndexTemplate)

        m.del_component('y')
예제 #8
0
    def test_simple_substitute_param(self):
        def diffeq(m, t, i):
            return m.dxdt[t, i] == t*m.x[t, i-1]**2 + m.y**2 + \
                m.x[t, i+1] + m.x[t, i-1]

        m = self.m
        t = IndexTemplate(m.TIME)
        e = diffeq(m, t, 2)

        self.assertTrue(isinstance(e, EXPR._ExpressionBase))

        _map = {}
        E = substitute_template_expression(e, substitute_getitem_with_param,
                                           _map)
        self.assertIsNot(e, E)

        self.assertEqual(len(_map), 3)

        idx1 = _GetItemIndexer(m.x[t, 1])
        self.assertIs(idx1._base, m.x)
        self.assertEqual(len(idx1._args), 2)
        self.assertIs(idx1._args[0], t)
        self.assertEqual(idx1._args[1], 1)
        self.assertIn(idx1, _map)

        idx2 = _GetItemIndexer(m.dxdt[t, 2])
        self.assertIs(idx2._base, m.dxdt)
        self.assertEqual(len(idx2._args), 2)
        self.assertIs(idx2._args[0], t)
        self.assertEqual(idx2._args[1], 2)
        self.assertIn(idx2, _map)

        idx3 = _GetItemIndexer(m.x[t, 3])
        self.assertIs(idx3._base, m.x)
        self.assertEqual(len(idx3._args), 2)
        self.assertIs(idx3._args[0], t)
        self.assertEqual(idx3._args[1], 3)
        self.assertIn(idx3, _map)

        self.assertFalse(idx1 == idx2)
        self.assertFalse(idx1 == idx3)
        self.assertFalse(idx2 == idx3)

        idx4 = _GetItemIndexer(m.x[t, 2])
        self.assertNotIn(idx4, _map)

        t.set_value(5)
        self.assertEqual((e._args[0](), e._args[1]()), (10, 136))

        self.assertEqual(
            str(E),
            'dxdt[{TIME},2]  ==  {TIME} * x[{TIME},1]**2.0 + y**2.0 + x[{TIME},3] + x[{TIME},1]'
        )

        _map[idx1].set_value(value(m.x[value(t), 1]))
        _map[idx2].set_value(value(m.dxdt[value(t), 2]))
        _map[idx3].set_value(value(m.x[value(t), 3]))
        self.assertEqual((E._args[0](), E._args[1]()), (10, 136))

        _map[idx1].set_value(12)
        _map[idx2].set_value(34)
        self.assertEqual((E._args[0](), E._args[1]()), (34, 738))
예제 #9
0
    def __init__(self, m, package='scipy'):
        
        self._intpackage = package
        if self._intpackage not in ['scipy', 'casadi']:
            raise DAE_Error(
                "Unrecognized simulator package %s. Please select from "
                "%s" % (self._intpackage, ['scipy', 'casadi']))

        if self._intpackage == 'scipy':
            if not scipy_available:
                # Converting this to a warning so that Simulator initialization
                # can be tested even when scipy is unavailable
                logger.warning("The scipy module is not available. You may "
                               "build the Simulator object but you will not "
                               "be able to run the simulation.")
            substituter = substitute_getitem_with_param
        else:
            if not casadi_available:
                # Initializing the simulator for use with casadi requires
                # access to casadi objects. Therefore, we must throw an error
                # here instead of a warning. 
                raise ValueError("The casadi module is not available. "
                                  "Cannot simulate model.")
            substituter = substitute_getitem_with_casadi_sym

        # Check for active Blocks and throw error if any are found
        if len(list(m.component_data_objects(Block, active=True,
                                             descend_into=False))):
            raise DAE_Error("The Simulator cannot handle hierarchical models "
                            "at the moment.")

        temp = m.component_map(ContinuousSet)
        if len(temp) != 1:
            raise DAE_Error(
                "Currently the simulator may only be applied to "
                "Pyomo models with a single ContinuousSet")

        # Get the ContinuousSet in the model
        contset = list(temp.values())[0]

        # Create a index template for the continuous set
        cstemplate = IndexTemplate(contset)

        # Ensure that there is at least one derivative in the model
        derivs = m.component_map(DerivativeVar)
        if len(derivs) == 0:
            raise DAE_Error("Cannot simulate a model with no derivatives")

        templatemap = {}  # Map for template substituter
        rhsdict = {}  # Map of derivative to its RHS templated expr
        derivlist = []  # Ordered list of derivatives
        alglist = []  # list of templated algebraic equations

        # Loop over constraints to find differential equations with separable
        # RHS. Must find a RHS for every derivative var otherwise ERROR. Build
        # dictionary of DerivativeVar:RHS equation.
        for con in m.component_objects(Constraint, active=True):
            
            # Skip the discretization equations if model is discretized
            if '_disc_eq' in con.name:
                continue
            
            # Check dimension of the Constraint. Check if the
            # Constraint is indexed by the continuous set and
            # determine its order in the indexing sets
            if con.dim() == 0:
                continue
            elif con._implicit_subsets is None:
                # Check if the continuous set is the indexing set
                if con._index is not contset:
                    continue
                else:
                    csidx = 0
                    noncsidx = (None,)
            else:
                temp = con._implicit_subsets
                dimsum = 0
                csidx = -1
                noncsidx = None
                for s in temp:
                    if s is contset:
                        if csidx != -1:
                            raise DAE_Error(
                                "Cannot simulate the constraint %s because "
                                "it is indexed by duplicate ContinuousSets"
                                % con.name)
                        csidx = dimsum
                    elif noncsidx is None:
                        noncsidx = s
                    else:
                        noncsidx = noncsidx.cross(s)
                    dimsum += s.dimen
                if csidx == -1:
                    continue

            # Get the rule used to construct the constraint
            conrule = con.rule

            for i in noncsidx:
                # Insert the index template and call the rule to
                # create a templated expression              
                if i is None:
                    tempexp = conrule(m, cstemplate)
                else:
                    if not isinstance(i, tuple):
                        i = (i,)
                    tempidx = i[0:csidx] + (cstemplate,) + i[csidx:]
                    tempexp = conrule(m, *tempidx)

                # Check to make sure it's an _EqualityExpression
                if not type(tempexp) is EXPR._EqualityExpression:
                    continue
            
                # Check to make sure it's a differential equation with
                # separable RHS
                args = None
                # Case 1: m.dxdt[t] = RHS 
                if type(tempexp._args[0]) is EXPR._GetItemExpression:
                    args = _check_getitemexpression(tempexp, 0)
            
                # Case 2: RHS = m.dxdt[t]
                if args is None:
                    if type(tempexp._args[1]) is EXPR._GetItemExpression:
                        args = _check_getitemexpression(tempexp, 1)

                # Case 3: m.p*m.dxdt[t] = RHS
                if args is None:
                    if type(tempexp._args[0]) is EXPR._ProductExpression:
                        args = _check_productexpression(tempexp, 0)

                # Case 4: RHS =  m.p*m.dxdt[t]
                if args is None:
                    if type(tempexp._args[1]) is EXPR._ProductExpression:
                        args = _check_productexpression(tempexp, 1)

                # Case 5: m.dxdt[t] + CONSTANT = RHS 
                # or CONSTANT + m.dxdt[t] = RHS
                if args is None:
                    if type(tempexp._args[0]) is EXPR._SumExpression:
                        args = _check_sumexpression(tempexp, 0)

                # Case 6: RHS = m.dxdt[t] + CONSTANT
                if args is None:
                    if type(tempexp._args[1]) is EXPR._SumExpression:
                        args = _check_sumexpression(tempexp, 1)

                # Case 7: RHS = m.p*m.dxdt[t] + CONSTANT
                # This case will be caught by Case 6 if p is immutable. If
                # p is mutable then this case will not be detected as a
                # separable differential equation

                # At this point if args is not None then args[0] contains
                # the _GetItemExpression for the DerivativeVar and args[1]
                # contains the RHS expression. If args is None then the
                # constraint is considered an algebraic equation
                if args is None:
                    # Constraint is an algebraic equation or unsupported
                    # differential equation
                    if self._intpackage == 'scipy':
                        raise DAE_Error(
                            "Model contains an algebraic equation or "
                            "unrecognized differential equation. Constraint "
                            "'%s' cannot be simulated using Scipy. If you are "
                            "trying to simulate a DAE model you must use "
                            "CasADi as the integration package."
                            % str(con.name))
                    tempexp = tempexp._args[0] - tempexp._args[1]
                    algexp = substitute_template_expression(tempexp,
                                                            substituter,
                                                            templatemap)
                    algexp = substitute_intrinsic_function(
                        algexp, substitute_intrinsic_function_with_casadi)
                    alglist.append(algexp)
                    continue
            
                # Add the differential equation to rhsdict and derivlist
                dv = args[0]
                RHS = args[1]
                dvkey = _GetItemIndexer(dv)
                if dvkey in rhsdict.keys():
                    raise DAE_Error(
                        "Found multiple RHS expressions for the "
                        "DerivativeVar %s" % str(dvkey))
            
                derivlist.append(dvkey)
                tempexp = substitute_template_expression(
                    RHS, substituter, templatemap)
                if self._intpackage is 'casadi':
                    # After substituting GetItemExpression objects
                    # replace intrinsic Pyomo functions with casadi
                    # functions 
                    tempexp = substitute_intrinsic_function(
                        tempexp, substitute_intrinsic_function_with_casadi)
                rhsdict[dvkey] = tempexp
        # Check to see if we found a RHS for every DerivativeVar in
        # the model
        # FIXME: Not sure how to rework this for multi-index case
        # allderivs = derivs.keys()
        # if set(allderivs) != set(derivlist):
        #     missing = list(set(allderivs)-set(derivlist))
        #     print("WARNING: Could not find a RHS expression for the "
        #     "following DerivativeVar components "+str(missing))

        # Create ordered list of differential variables corresponding
        # to the list of derivatives.
        diffvars = []

        for deriv in derivlist:
            sv = deriv._base.get_state_var()
            diffvars.append(_GetItemIndexer(sv[deriv._args]))

        # Create ordered list of algebraic variables and time-varying
        # parameters
        algvars = []

        for item in iterkeys(templatemap):
            if item._base.name in derivs.keys():
                # Make sure there are no DerivativeVars in the
                # template map
                raise DAE_Error(
                    "Cannot simulate a differential equation with "
                    "multiple DerivativeVars")
            if item not in diffvars:
                # Finds time varying parameters and algebraic vars
                algvars.append(item)
                
        if self._intpackage == 'scipy':
            # Function sent to scipy integrator
            def _rhsfun(t, x):
                residual = []
                cstemplate.set_value(t)
                for idx, v in enumerate(diffvars):
                    if v in templatemap:
                        templatemap[v].set_value(x[idx])

                for d in derivlist:
                    residual.append(rhsdict[d]())

                return residual
            self._rhsfun = _rhsfun   
            
        self._contset = contset
        self._cstemplate = cstemplate
        self._diffvars = diffvars
        self._derivlist = derivlist
        self._templatemap = templatemap
        self._rhsdict = rhsdict
        self._alglist = alglist
        self._algvars = algvars
        self._model = m
        self._tsim = None
        self._simsolution = None
        # The algebraic vars in the most recent simulation
        self._simalgvars = None
        # The time-varying inputs in the most recent simulation
        self._siminputvars = None