Beispiel #1
0
def I_CR(t):
    """
    Test light input function. 9500lux from t=10 to 11.5
    """
    return 150 * cs.heaviside(t - cs.floor(t / 24) * 24 -
                              8) - 150 * cs.heaviside(t - cs.floor(t / 24) *
                                                      24 - 24)
Beispiel #2
0
def floor(x):
    return ca.floor(x)
Beispiel #3
0
def solve_bnb(solver, root, integers):
    """A branch and bound solver which uses IPOPT as the IP subproblem module"""
    # Initialize the node queue
    Q = [(numpy.inf, root)]

    # Global solution data
    x_opt = None
    f_opt = numpy.inf

    # Continuous solution data
    x0 = None
    f0 = numpy.inf

    # Main loop
    seqnum = 0
    while Q:
        seqnum += 1

        # Extract node with lowest lower bound and check if fathoming is necessary
        # (should not happen)
        node = Q.pop()
        if f_opt < numpy.inf and node[0] >= f_opt:
            print "Node %4d (%4d left): %9g >= %9g - PRE-FATHOM" % (
                seqnum, len(Q), node[0], f_opt)
            continue
        node = node[1]

        # Solve the node
        result = solver(lbx=node['lbx'],
                        ubx=node['ubx'],
                        lbg=node['lbg'],
                        ubg=node['ubg'])

        # Local solution data
        x = result['x']
        f = result['f']

        # Store continuous solution data if none has been stored yet
        if x0 is None:
            x0 = casadi.DM(x)
            f0 = f

        # Check if branch can be fathomed
        if f >= f_opt:
            print "Node %4d (%4d left): %9g >= %9g - POST-FATHOM" % (
                seqnum, len(Q), f, f_opt)
            continue

        # Check for violations of integrality (fixed tolerance 1e-5)
        viol = [abs(casadi.floor(x[i] + 0.5) - x[i]) for i in integers]
        idx = [(integers[i], viol[i]) for i in range(len(integers))
               if viol[i] > 1e-5]
        if not idx:
            # Register new global solution
            x_opt = x
            f_opt = f

            # Cull the branch and bound tree
            pre = len(Q)
            Q = [n for n in Q if n[0] < f_opt]
            post = len(Q)

            print "Node %4d (%4d left): f_opt = %9g - *** SOLUTION *** (%d culled)" % (
                seqnum, len(Q), f, pre - post)
        else:
            # Branch on first violation
            idx = idx[0][0]

            # Generate two new nodes (could reuse node structure)
            ln = {
                'x0': casadi.DM(x),
                'lbx': node['lbx'],
                'ubx': casadi.DM(node['ubx']),
                'lbg': node['lbg'],
                'ubg': node['ubg'],
                'lam_x0': casadi.DM(result['lam_x']),
                'lam_g0': casadi.DM(result['lam_g'])
            }
            un = {
                'x0': casadi.DM(x),
                'lbx': casadi.DM(node['lbx']),
                'ubx': node['ubx'],
                'lbg': node['lbg'],
                'ubg': node['ubg'],
                'lam_x0': casadi.DM(result['lam_x']),
                'lam_g0': casadi.DM(result['lam_g'])
            }

            ln['ubx'][idx] = casadi.floor(x[idx])
            un['lbx'][idx] = casadi.ceil(x[idx])

            lower_node = (f, ln)
            upper_node = (f, un)

            # Insert new nodes in queue (inefficient for large queues)
            Q.extend([lower_node, upper_node])
            Q.sort(cmp=lambda x, y: cmp(y[0], x[0]))
            print "Node %4d (%4d left): %9g - BRANCH ON %d" % (seqnum, len(Q),
                                                               f, idx)

    return {'x0': x0, 'f0': f0, 'x': x_opt, 'f': f_opt}
Beispiel #4
0
    def _convert(self, symbol, t, y, y_dot, inputs):
        """ See :meth:`CasadiConverter.convert()`. """
        if isinstance(
                symbol,
            (
                pybamm.Scalar,
                pybamm.Array,
                pybamm.Time,
                pybamm.InputParameter,
                pybamm.ExternalVariable,
            ),
        ):
            return casadi.MX(symbol.evaluate(t, y, y_dot, inputs))

        elif isinstance(symbol, pybamm.StateVector):
            if y is None:
                raise ValueError(
                    "Must provide a 'y' for converting state vectors")
            return casadi.vertcat(*[y[y_slice] for y_slice in symbol.y_slices])

        elif isinstance(symbol, pybamm.StateVectorDot):
            if y_dot is None:
                raise ValueError(
                    "Must provide a 'y_dot' for converting state vectors")
            return casadi.vertcat(
                *[y_dot[y_slice] for y_slice in symbol.y_slices])

        elif isinstance(symbol, pybamm.BinaryOperator):
            left, right = symbol.children
            # process children
            converted_left = self.convert(left, t, y, y_dot, inputs)
            converted_right = self.convert(right, t, y, y_dot, inputs)

            if isinstance(symbol, pybamm.Modulo):
                return casadi.fmod(converted_left, converted_right)
            if isinstance(symbol, pybamm.Minimum):
                return casadi.fmin(converted_left, converted_right)
            if isinstance(symbol, pybamm.Maximum):
                return casadi.fmax(converted_left, converted_right)

            # _binary_evaluate defined in derived classes for specific rules
            return symbol._binary_evaluate(converted_left, converted_right)

        elif isinstance(symbol, pybamm.UnaryOperator):
            converted_child = self.convert(symbol.child, t, y, y_dot, inputs)
            if isinstance(symbol, pybamm.AbsoluteValue):
                return casadi.fabs(converted_child)
            if isinstance(symbol, pybamm.Floor):
                return casadi.floor(converted_child)
            if isinstance(symbol, pybamm.Ceiling):
                return casadi.ceil(converted_child)
            return symbol._unary_evaluate(converted_child)

        elif isinstance(symbol, pybamm.Function):
            converted_children = [
                self.convert(child, t, y, y_dot, inputs)
                for child in symbol.children
            ]
            # Special functions
            if symbol.function == np.min:
                return casadi.mmin(*converted_children)
            elif symbol.function == np.max:
                return casadi.mmax(*converted_children)
            elif symbol.function == np.abs:
                return casadi.fabs(*converted_children)
            elif symbol.function == np.sqrt:
                return casadi.sqrt(*converted_children)
            elif symbol.function == np.sin:
                return casadi.sin(*converted_children)
            elif symbol.function == np.arcsinh:
                return casadi.arcsinh(*converted_children)
            elif symbol.function == np.arccosh:
                return casadi.arccosh(*converted_children)
            elif symbol.function == np.tanh:
                return casadi.tanh(*converted_children)
            elif symbol.function == np.cosh:
                return casadi.cosh(*converted_children)
            elif symbol.function == np.sinh:
                return casadi.sinh(*converted_children)
            elif symbol.function == np.cos:
                return casadi.cos(*converted_children)
            elif symbol.function == np.exp:
                return casadi.exp(*converted_children)
            elif symbol.function == np.log:
                return casadi.log(*converted_children)
            elif symbol.function == np.sign:
                return casadi.sign(*converted_children)
            elif symbol.function == special.erf:
                return casadi.erf(*converted_children)
            elif isinstance(symbol.function, (PchipInterpolator, CubicSpline)):
                return casadi.interpolant("LUT", "bspline", [symbol.x],
                                          symbol.y)(*converted_children)
            elif symbol.function.__name__.startswith("elementwise_grad_of_"):
                differentiating_child_idx = int(symbol.function.__name__[-1])
                # Create dummy symbolic variables in order to differentiate using CasADi
                dummy_vars = [
                    casadi.MX.sym("y_" + str(i))
                    for i in range(len(converted_children))
                ]
                func_diff = casadi.gradient(
                    symbol.differentiated_function(*dummy_vars),
                    dummy_vars[differentiating_child_idx],
                )
                # Create function and evaluate it using the children
                casadi_func_diff = casadi.Function("func_diff", dummy_vars,
                                                   [func_diff])
                return casadi_func_diff(*converted_children)
            # Other functions
            else:
                return symbol._function_evaluate(converted_children)
        elif isinstance(symbol, pybamm.Concatenation):
            converted_children = [
                self.convert(child, t, y, y_dot, inputs)
                for child in symbol.children
            ]
            if isinstance(symbol,
                          (pybamm.NumpyConcatenation, pybamm.SparseStack)):
                return casadi.vertcat(*converted_children)
            # DomainConcatenation specifies a particular ordering for the concatenation,
            # which we must follow
            elif isinstance(symbol, pybamm.DomainConcatenation):
                slice_starts = []
                all_child_vectors = []
                for i in range(symbol.secondary_dimensions_npts):
                    child_vectors = []
                    for child_var, slices in zip(converted_children,
                                                 symbol._children_slices):
                        for child_dom, child_slice in slices.items():
                            slice_starts.append(
                                symbol._slices[child_dom][i].start)
                            child_vectors.append(
                                child_var[child_slice[i].start:child_slice[i].
                                          stop])
                    all_child_vectors.extend([
                        v for _, v in sorted(zip(slice_starts, child_vectors))
                    ])
                return casadi.vertcat(*all_child_vectors)

        else:
            raise TypeError("""
                Cannot convert symbol of type '{}' to CasADi. Symbols must all be
                'linear algebra' at this stage.
                """.format(type(symbol)))
 def wraptopi(x):
     angle_rad = x - 2 * pi * ca.floor((x + pi) / (2 * pi))
     return angle_rad