def link_consumption(T, f, g, M): L = f(T) R = g(T) max_t_idx = np.iinfo(np.dtype('uint32')).max opt_H = np.full_like(L, float('inf')) opt_delta_idx = np.full_like(L, max_t_idx, dtype='uint32') for d_idx in range(len(L)): R_d = np.roll(R, d_idx) R_d[:d_idx] = float('inf') if L[d_idx] >= float('inf'): continue H_d = np.maximum(0, L[d_idx] + R_d) H_d[R_d >= float('inf')] = float('inf') index = opt_H > H_d opt_H[index] = H_d[index] opt_delta_idx[index] = d_idx opt_H[opt_H > M] = float('inf') opt_delta_idx[opt_H > M] = max_t_idx opt_delta = np.full_like(T, float('inf'), dtype='float') opt_delta[opt_delta_idx < max_t_idx] = T[opt_delta_idx[ opt_delta_idx < max_t_idx]] d = PiecewiseFunction( T, np.concatenate((make_piecewise_linear(T, opt_delta), [LinearFunction(0, opt_delta[-1])]))) h = PiecewiseFunction( T, np.concatenate( (make_piecewise_linear(T, opt_H), [LinearFunction(0, opt_H[-1])]))) return d, h
def test_lin_lin_same_linking(self): T = np.arange(0, 20, eps) M = 10 f = PiecewiseFunction([0], [LinearFunction(0, 5)]) g = PiecewiseFunction([0], [LinearFunction(0, 5)]) numeric_opt_d, numeric_h = numeric.link_consumption(T, f, g, M) analytic_opt_d, analytic_h = analytic.link_consumption(f, g) self.assertTrue(equal("opt_d", T, numeric_opt_d, analytic_opt_d)) self.assertTrue(equal("h", T, numeric_h, analytic_h)) self.assertEqual(analytic_h(0), 10) self.assertEqual(analytic_h(20), 10)
def test_linking_analytic(self): link_consumption = lambda f, g, M: analytic.link_consumption(f, g) link_charging = lambda f, cf, M: analytic.link_charging(f, cf, M) f = PiecewiseFunction([0], [LinearFunction(0, 5)]) cf = PiecewiseFunction( [0, 10], [LinearFunction(1, 0), LinearFunction(0, 10)]) graph = Graph([(0, 1, (False, f)), (1, 2, (True, cf))]) ds, h = link_path(graph, [0, 1, 2], 10, link_consumption, link_charging) self.assertEqual(h(0), 5) self.assertEqual(h(5), 0)
def test_linking_lin_cf(self): T = np.arange(0, 20, eps) M = 10 f = PiecewiseFunction([0], [LinearFunction(0, 5)]) cf = PiecewiseFunction( [0, 10], [LinearFunction(1, 0), LinearFunction(0, 10)]) numeric_opt_d, numeric_h = numeric.link_charging(T, f, cf, M) analytic_opt_d, analytic_h = analytic.link_charging(f, cf, M) self.assertTrue(equal("opt_d", T, numeric_opt_d, analytic_opt_d)) self.assertTrue(equal("h", T, numeric_h, analytic_h)) self.assertEqual(analytic_h(0), 5) self.assertEqual(analytic_h(10), 0)
def test_linking_numeric(self): T = np.arange(0, 20, 0.1) link_consumption = lambda f, g, M: numeric.link_consumption(T, f, g, M) link_charging = lambda f, cf, M: numeric.link_charging(T, f, cf, M) f = PiecewiseFunction([0], [LinearFunction(0, 5)]) cf = PiecewiseFunction( [0, 10], [LinearFunction(1, 0), LinearFunction(0, 10)]) graph = Graph([(0, 1, (False, f)), (1, 2, (True, cf))]) ds, h = link_path(graph, [0, 1, 2], 10, link_consumption, link_charging) self.assertEqual(h(0), 5) self.assertEqual(h(5), 0)
def link_charging(T, f, cf, M): L = f(T) CF = cf(T) max_t_idx = np.iinfo(np.dtype('uint32')).max opt_H = np.full_like(L, float('inf')) opt_delta_idx = np.full_like(L, max_t_idx, dtype='uint32') ts = [] for d_idx in range(len(L)): if L[d_idx] >= float('inf'): continue y = M - L[d_idx] if y < 0: continue assert (y <= M) t_idx = np.argmax(CF > y) CF_y = np.roll(CF, -t_idx) CF_y[-t_idx:] = CF[-1] assert (len(CF_y) == len(L)) CF_d = np.roll(CF_y, d_idx) CF_d[:d_idx] = -float('inf') H_d = np.maximum(0, M - CF_d) index = opt_H > H_d opt_H[index] = H_d[index] opt_delta_idx[index] = d_idx opt_H[opt_H > M] = float('inf') opt_delta_idx[opt_H > M] = max_t_idx print(list(ts)) opt_delta = np.full_like(T, float('inf'), dtype='float') opt_delta[opt_delta_idx < max_t_idx] = T[opt_delta_idx[ opt_delta_idx < max_t_idx]] d = PiecewiseFunction( T, np.concatenate((make_piecewise_linear(T, opt_delta), [LinearFunction(0, opt_delta[-1])]))) h = PiecewiseFunction( T, np.concatenate( (make_piecewise_linear(T, opt_H), [LinearFunction(0, opt_H[-1])]))) return d, h
def test_linking_hyp_cf(self): T = np.arange(0, 20, eps) M = 10 f = PiecewiseFunction([0, 2, 6], [ LinearFunction(0, float('inf')), HypLinFunction(5, 1, 1, 0), LinearFunction(0, 6 / 5.) ]) cf = PiecewiseFunction( [0, 10], [LinearFunction(1, 0), LinearFunction(0, 10)]) numeric_opt_d, numeric_h = numeric.link_charging(T, f, cf, M) analytic_opt_d, analytic_h = analytic.link_charging(f, cf, M) # Wrong due to numeric instabilities between 3.16 and 40 #self.assertTrue(equal("opt_d", T, numeric_opt_d, analytic_opt_d)) self.assertTrue( equal("opt_d", T[T < 3.16], numeric_opt_d, analytic_opt_d)) self.assertTrue(equal("h", T, numeric_h, analytic_h)) self.assertEqual(analytic_h(0), float('inf')) self.assertEqual(analytic_h(2), 6) self.assertEqual(analytic_h(8), 0)
def test_hyp_lin_linking(self): T = np.arange(0, 20, eps) M = 10 f = PiecewiseFunction([0, 2, 6], [ LinearFunction(0, float('inf')), HypLinFunction(5, 1, 1, 0), LinearFunction(0, 6 / 5.) ]) self.assertEqual(f(2), 6) self.assertEqual(f(6), 1.2) self.assertEqual(f(10), 1.2) g = PiecewiseFunction([0, 4, 9], [ LinearFunction(0, float('inf')), LinearFunction(-1, 9), LinearFunction(0, 0) ]) numeric_opt_d, numeric_h = numeric.link_consumption(T, f, g, M) analytic_opt_d, analytic_h = analytic.link_consumption(f, g) self.assertTrue(equal("opt_d", T, numeric_opt_d, analytic_opt_d)) self.assertTrue(equal("h", T, numeric_h, analytic_h)) self.assertEqual(analytic_h(6), 11) self.assertEqual(analytic_h(16), 6 / 5.)
def link_path(graph, path, M, link_consumption, link_charging, initial_soc=None): """Takes graph with data of form (is_charging, weight_function) and link_consumption(f, g, M), link_charging(f, cf, M). Returns a tuple (optimal_deltas, consumption) """ if initial_soc is None: initial_soc = M consumption = PiecewiseFunction([0], [LinearFunction(M - initial_soc, 0)]) ds = [] for u, v in zip(path[:-1], path[1:]): is_charging, w = graph.data(graph.edge(u, v)) if is_charging: opt_d, consumption = link_charging(consumption, w, M) else: opt_d, consumption = link_consumption(consumption, w, M) ds.append(opt_d) return ds, consumption