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)
def floor(x): return ca.floor(x)
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}
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