def _session_generation_helper( max_rate_list: List[Union[float, np.ndarray]], upper_bound_estimate: Dict[str, float], expected_max: float, expected_min: float, min_rate_list: Optional[List[Union[float, np.ndarray]]] = None, ) -> None: if min_rate_list is not None: min_rate_list *= N sessions: List[SessionDict] = session_generator( num_sessions=N, arrivals=[ARRIVAL_TIME] * N, departures=[ARRIVAL_TIME + SESSION_DUR] * N, requested_energy=[3.3] * N, remaining_energy=[3.3] * N, max_rates=max_rate_list * N, min_rates=min_rate_list, ) sessions: List[SessionInfo] = [SessionInfo(**s) for s in sessions] rd = Mock() rd.get_maximum_rates = Mock(return_value=upper_bound_estimate) modified_sessions = apply_upper_bound_estimate(rd, sessions) for session in modified_sessions: nptest.assert_almost_equal(session.max_rates, expected_max) nptest.assert_almost_equal(session.min_rates, expected_min)
def _session_generation_helper( max_rates: List[Union[float, np.ndarray]], min_rates: List[Union[float, np.ndarray]], ) -> List[SessionInfo]: sessions: List[SessionDict] = session_generator( num_sessions=N, arrivals=[ARRIVAL_TIME] * N, departures=[ARRIVAL_TIME + SESSION_DUR] * N, requested_energy=[3.3] * N, remaining_energy=[3.3] * N, max_rates=max_rates, min_rates=min_rates, ) sessions: List[SessionInfo] = [SessionInfo(**s) for s in sessions] # Since we want to test the expand function but the SessionInfo constructor # already expands the max/min rates, we manually set the max/min rates back to # the input max_rates/min_rates (possibly scalars) after construction. def _set_bounds(session: SessionInfo, max_rate: float, min_rate: float) -> SessionInfo: session.max_rates = max_rate session.min_rates = min_rate return session sessions: List[SessionInfo] = [ _set_bounds(session, max_rates[i], min_rates[i]) for i, session in enumerate(sessions) ] return expand_max_min_rates(sessions)
def reconcile_max_and_min(session: SessionInfo, choose_min: bool = True) -> SessionInfo: """ Modify session.max_rates[t] to equal session.min_rates[t] for times when max_rates[t] < min_rates[t] Args: session (SessionInfo): Session object. choose_min (bool): If True, when in conflict defer to the minimum rate. If False, defer to maximum. Returns: SessionInfo: session modified such that max_rates[t] is never less than min_rates[t] """ mask = session.max_rates < session.min_rates if choose_min: session.max_rates[mask] = session.min_rates[mask] else: session.min_rates[mask] = session.max_rates[mask] return session
def active_sessions(self) -> List[SessionInfo]: """ Return a list of SessionInfo objects describing the currently charging EVs. Returns: List[SessionInfo]: List of currently active charging sessions. """ active_sessions = self._get_or_error("active_sessions") return [ SessionInfo(current_time=self.current_time, **session) for session in active_sessions ]
def test_proper_length_min_rates(self) -> None: s = SessionInfo("PS-001", "01", 10, 4, 5, 10, estimated_departure=12, min_rates=[8.0] * 5) self.assertEqual(s.min_rates.shape, (5, )) nptest.assert_array_equal(s.min_rates, 8.0)
def test_kwarg_order(self) -> None: """ Tests that the order of overflow of kwargs for SessionInfo is maintained. """ s = SessionInfo("PS-001", "01", 10, 4, 5, 60, 63, 6, [8.0] * 54, [32.0] * 54) self.assertEqual(s.estimated_departure, 63) self.assertEqual(s.current_time, 6) nptest.assert_array_equal(s.min_rates, 8.0) self.assertEqual(s.min_rates.shape, (54, )) nptest.assert_array_equal(s.max_rates, 32.0) self.assertEqual(s.max_rates.shape, (54, ))
def test_min_rates_too_short(self) -> None: with self.assertRaises(ValueError): SessionInfo( "PS-001", "01", 10, 4, 5, 10, estimated_departure=12, min_rates=[8.0] * 4, )
def test_valid_inputs_nonzero_current_time_less_than_arrival(self) -> None: s = SessionInfo("PS-001", "01", 10, 4, 5, 60, estimated_departure=63, current_time=4) self.assertEqual(s.current_time, 4) self.assertEqual(s.arrival_offset, 1) self.assertEqual(s.remaining_time, 55)
def _session_generation_helper(max_rates: int, choose_min: bool = True) -> SessionInfo: session = SessionInfo( station_id="1", session_id="1", requested_energy=3.3, energy_delivered=0, arrival=0, departure=5, max_rates=max_rates, min_rates=8, ) return reconcile_max_and_min(session, choose_min=choose_min)
def test_pilot_less_than_existing_max(self) -> None: # pylint: disable=no-self-use sessions = session_generator( num_sessions=N, arrivals=[ARRIVAL_TIME] * N, departures=[ARRIVAL_TIME + SESSION_DUR] * N, requested_energy=[3.3] * N, remaining_energy=[3.3] * N, max_rates=[np.repeat(40, SESSION_DUR)] * N, ) sessions = [SessionInfo(**s) for s in sessions] infrastructure = InfrastructureInfo( **single_phase_single_constraint(num_evses=N, limit=32)) modified_sessions = enforce_pilot_limit(sessions, infrastructure) for session in modified_sessions: nptest.assert_almost_equal(session.max_rates, 32)
def _test_remove_sessions_within_threshold( self, remaining_energies: List[float]) -> None: sessions = session_generator( num_sessions=N, arrivals=[1, 2, 3], departures=[1 + SESSION_DUR, 2 + SESSION_DUR, 3 + SESSION_DUR], requested_energy=[3.3] * N, remaining_energy=remaining_energies, max_rates=[np.repeat(32, SESSION_DUR)] * N, ) infrastructure = InfrastructureInfo( **three_phase_balanced_network(1, limit=100)) sessions = [SessionInfo(**s) for s in sessions] modified_sessions = remove_finished_sessions(sessions, infrastructure, 5) self.assertEqual(len(modified_sessions), 2)
def test_valid_inputs_w_defaults(self) -> None: s = SessionInfo("PS-001", "01", 10, 4, 5, 60) self.assertEqual(s.station_id, "PS-001") self.assertEqual(s.session_id, "01") self.assertEqual(s.requested_energy, 10) self.assertEqual(s.energy_delivered, 4) self.assertEqual(s.arrival, 5) self.assertEqual(s.departure, 60) self.assertEqual(s.estimated_departure, 60) self.assertEqual(s.current_time, 0) nptest.assert_array_equal(s.min_rates, 0) self.assertEqual(s.min_rates.shape, (55, )) nptest.assert_array_equal(s.max_rates, float("inf")) self.assertEqual(s.max_rates.shape, (55, )) self.assertEqual(s.remaining_demand, 6) self.assertEqual(s.arrival_offset, 5) self.assertEqual(s.remaining_time, 55)
def test_partial_estimator(self) -> None: # pylint: disable=no-self-use sessions: List[SessionDict] = session_generator( num_sessions=N, arrivals=[ARRIVAL_TIME] * N, departures=[ARRIVAL_TIME + SESSION_DUR] * N, requested_energy=[3.3] * N, remaining_energy=[3.3] * N, max_rates=[32] * N, ) sessions: List[SessionInfo] = [SessionInfo(**s) for s in sessions] rd = Mock() rd.get_maximum_rates = Mock( return_value={f"{i}": [16] * 5 for i in range(N) if i != 1}) modified_sessions = apply_upper_bound_estimate(rd, sessions) for i, session in enumerate(modified_sessions): nptest.assert_almost_equal(session.max_rates, (16 if i != 1 else 32)) nptest.assert_almost_equal(session.min_rates, 0)
def test_apply_min_infeasible(self) -> None: # pylint: disable=no-self-use sessions = session_generator( num_sessions=N, arrivals=[1, 2, 3], departures=[1 + SESSION_DUR, 2 + SESSION_DUR, 3 + SESSION_DUR], requested_energy=[3.3] * N, remaining_energy=[3.3] * N, max_rates=[np.repeat(32, SESSION_DUR)] * N, ) sessions = [SessionInfo(**s) for s in sessions] infrastructure = InfrastructureInfo( **single_phase_single_constraint(N, 16)) modified_sessions = apply_minimum_charging_rate( sessions, infrastructure, PERIOD) for i in range(2): nptest.assert_almost_equal(modified_sessions[i].min_rates[0], 8) nptest.assert_almost_equal(modified_sessions[i].min_rates[1:], 0) # It is not feasible to deliver 8 A to session '2', so max and # min should be 0 at time t=0. nptest.assert_almost_equal(modified_sessions[2].min_rates, 0) nptest.assert_almost_equal(modified_sessions[2].max_rates[0], 0)
def _session_generation_helper( max_rate_list: List[Union[float, np.ndarray]], min_rate_list: Optional[List[Union[float, np.ndarray]]] = None, remaining_energy: float = 3.3, ) -> List[SessionInfo]: if min_rate_list is not None: min_rate_list *= N sessions: List[SessionDict] = session_generator( num_sessions=N, arrivals=[ARRIVAL_TIME] * N, departures=[ARRIVAL_TIME + SESSION_DUR] * N, requested_energy=[3.3] * N, remaining_energy=[remaining_energy] * N, max_rates=max_rate_list * N, min_rates=min_rate_list, ) sessions: List[SessionInfo] = [SessionInfo(**s) for s in sessions] infrastructure = InfrastructureInfo( **single_phase_single_constraint(N, 32)) modified_sessions = apply_minimum_charging_rate( sessions, infrastructure, PERIOD) return modified_sessions
def _set_bounds(session: SessionInfo, max_rate: float, min_rate: float) -> SessionInfo: session.max_rates = max_rate session.min_rates = min_rate return session
def test_valid_inputs_distinct_estimated_departure(self) -> None: s = SessionInfo("PS-001", "01", 10, 4, 5, 60, estimated_departure=63) self.assertEqual(s.departure, 60) self.assertEqual(s.estimated_departure, 63)