From 3a99709e752775e8392bc4b48ca8ea987c40614c Mon Sep 17 00:00:00 2001 From: rfitzger Date: Fri, 22 Sep 2023 12:40:35 -0600 Subject: [PATCH 1/9] improve error message for power_type arg --- .../vehicle/mechatronics/powercurve/tabular_powercurve.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nrel/hive/model/vehicle/mechatronics/powercurve/tabular_powercurve.py b/nrel/hive/model/vehicle/mechatronics/powercurve/tabular_powercurve.py index aa67e7cc..6565a8bd 100644 --- a/nrel/hive/model/vehicle/mechatronics/powercurve/tabular_powercurve.py +++ b/nrel/hive/model/vehicle/mechatronics/powercurve/tabular_powercurve.py @@ -55,8 +55,14 @@ def __init__( self.step_size_seconds = data["step_size_seconds"] # seconds if self.energy_type is None: + pt = data.get("power_type") + if pt is None: + pt_msg = "no power_type argument" + else: + pt_msg = f"invalid energy type '{data['power_type']}'" raise AttributeError( - f"TabularPowercurve initialized with invalid energy type {self.energy_type}" + f"TabularPowercurve configuration has {pt_msg}; " + f"should be one of {{electric, gasoline}} " ) charging_model = sorted(data["power_curve"], key=lambda x: x["energy_kwh"]) From aed1636b508a7cfab9d2f66487de416b7eecdbbb Mon Sep 17 00:00:00 2001 From: rfitzger Date: Wed, 27 Sep 2023 15:14:52 -0600 Subject: [PATCH 2/9] remove use of literal_eval --- nrel/hive/model/roadnetwork/link_id.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nrel/hive/model/roadnetwork/link_id.py b/nrel/hive/model/roadnetwork/link_id.py index 45dc1783..2a28758b 100644 --- a/nrel/hive/model/roadnetwork/link_id.py +++ b/nrel/hive/model/roadnetwork/link_id.py @@ -1,6 +1,4 @@ -from ast import literal_eval from typing import Optional, Tuple, Any - from nrel.hive.util.typealiases import LinkId NodeId = Any @@ -39,8 +37,8 @@ def extract_node_ids( ) else: try: - src = literal_eval(result[0]) - dst = literal_eval(result[1]) + src = str(result[0]) + dst = str(result[1]) except ValueError: return Exception(f"LinkId {link_id} cannot be parsed."), None From a829e912a91dc5cd02beb96c7180ef2e1ea058b2 Mon Sep 17 00:00:00 2001 From: rfitzger Date: Thu, 28 Sep 2023 15:31:43 -0600 Subject: [PATCH 3/9] helper to extract node ids as integers --- nrel/hive/model/roadnetwork/link_id.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/nrel/hive/model/roadnetwork/link_id.py b/nrel/hive/model/roadnetwork/link_id.py index 2a28758b..ae0dc96f 100644 --- a/nrel/hive/model/roadnetwork/link_id.py +++ b/nrel/hive/model/roadnetwork/link_id.py @@ -45,6 +45,29 @@ def extract_node_ids( return None, (src, dst) +def extract_node_ids_int( + link_id: LinkId +) -> Tuple[Optional[Exception], Optional[Tuple[int, int]]]: + """node ids can be strings for the haversine case but for networkx graphs they must be + integers as they are treated as indices. + + :param link_id: link id to read + :type link_id: LinkId + :return: _description_ + :rtype: Tuple[Optional[Exception], Optional[Tuple[int, int]]] + """ + err, ids = extract_node_ids(link_id) + if err is not None or ids is None: + return err, None + else: + try: + src_str, dst_str = ids + src = int(src_str) + dst = int(dst_str) + return None, (src, dst) + except ValueError as e: + return e, None + def reverse_link_id( link_id: LinkId, ) -> Tuple[Optional[Exception], Optional[LinkId]]: From d20fd5ea17e3f6e8751aabdbd830997a68ca60ac Mon Sep 17 00:00:00 2001 From: rfitzger Date: Thu, 28 Sep 2023 15:31:50 -0600 Subject: [PATCH 4/9] logging --- nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py b/nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py index afa7a541..dd683505 100644 --- a/nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py +++ b/nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py @@ -10,7 +10,7 @@ from nrel.hive.model.entity_position import EntityPosition from nrel.hive.model.roadnetwork.link import Link -from nrel.hive.model.roadnetwork.link_id import extract_node_ids +from nrel.hive.model.roadnetwork.link_id import extract_node_ids_int from nrel.hive.model.roadnetwork.osm.osm_builders import osm_graph_from_polygon from nrel.hive.model.roadnetwork.osm.osm_road_network_link_helper import OSMRoadNetworkLinkHelper from nrel.hive.model.roadnetwork.osm.osm_roadnetwork_ops import ( @@ -50,6 +50,7 @@ def __init__( # validate network # road network must be strongly connected + log.info(f"testing graph connectivity") if not nx.is_strongly_connected(graph): raise RuntimeError("Only strongly connected graphs are allowed.") @@ -66,6 +67,7 @@ def _valid_node_id(nid: Union[int, tuple]) -> bool: raise TypeError("all node ids must be either an integer or a tuple of integers") # check to make sure the graph has the right information on the links + log.info(f"testing graph speed data") missing_speed = 0 missing_time = 0 for u, v, d in graph.edges(data=True): @@ -98,6 +100,7 @@ def _valid_node_id(nid: Union[int, tuple]) -> bool: ) # build tables on the network edges for spatial lookup and LinkId lookup + log.info(f"building spatial index for graph") link_helper_error, link_helper = OSMRoadNetworkLinkHelper.build( graph, sim_h3_resolution, default_speed_kmph ) @@ -155,6 +158,7 @@ def from_file( if road_network_path.suffix == ".json": with road_network_path.open("r") as f: graph = nx.node_link_graph(json.load(f)) + log.info(f"loaded graph with {len(graph.edges)} edges") return OSMRoadNetwork(graph, sim_h3_resolution, default_speed_kmph) else: raise TypeError( @@ -188,8 +192,8 @@ def _astar_cost_heuristic(source, dest) -> float: # start path search from the end of the origin link, terminate search at the start of the # destination link - extract_src_err, src_nodes = extract_node_ids(origin.link_id) - extract_dst_err, dst_nodes = extract_node_ids(destination.link_id) + extract_src_err, src_nodes = extract_node_ids_int(origin.link_id) + extract_dst_err, dst_nodes = extract_node_ids_int(destination.link_id) if extract_src_err: log.error(extract_src_err) return empty_route() From 3b3cd50565a3cdcc6d3f0589644144902278883b Mon Sep 17 00:00:00 2001 From: rfitzger Date: Thu, 28 Sep 2023 15:32:11 -0600 Subject: [PATCH 5/9] avoid built-in "id" name --- nrel/hive/model/station/station.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/nrel/hive/model/station/station.py b/nrel/hive/model/station/station.py index 71f0cff4..f5f3b9b7 100644 --- a/nrel/hive/model/station/station.py +++ b/nrel/hive/model/station/station.py @@ -70,7 +70,7 @@ def geoid(self) -> GeoId: @classmethod def build( cls, - id: StationId, + station_id: StationId, geoid: GeoId, road_network: RoadNetwork, chargers: immutables.Map[ChargerId, int], @@ -100,7 +100,7 @@ def _chargers(acc, charger_data): charger = env.chargers.get(charger_id) if charger is None: msg = ( - f"attempting to create station {id} with charger type {charger_id} " + f"attempting to create station {station_id} with charger type {charger_id} " f"but that charger type has not been defined for this scenario" ) return TypeError(msg), None @@ -114,7 +114,7 @@ def _chargers(acc, charger_data): if error is not None: raise error if charger_states is None: - msg = f"internal error after building station chargers for station {id}" + msg = f"internal error after building station chargers for station {station_id}" raise Exception(msg) energy_dispensed = immutables.Map({energy_type: 0.0 for energy_type in EnergyType}) @@ -122,12 +122,12 @@ def _chargers(acc, charger_data): if position is None: msg = ( "could not find a road network position matching the position " - f"provided for station {id}" + f"provided for station {station_id}" ) raise H3Error(msg) return Station( - id=id, + id=station_id, position=position, state=charger_states, energy_dispensed=energy_dispensed, @@ -222,7 +222,7 @@ def from_row( elif station_id not in builder: # create this station return Station.build( - id=station_id, + station_id=station_id, geoid=geoid, road_network=road_network, chargers=immutables.Map({charger_id: charger_count}), From 9eb124b29ec2abb6a9d07c33a769fe00d220b950 Mon Sep 17 00:00:00 2001 From: rfitzger Date: Thu, 28 Sep 2023 15:32:25 -0600 Subject: [PATCH 6/9] split out lines for breakpoints, logging --- nrel/hive/model/vehicle/mechatronics/bev.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nrel/hive/model/vehicle/mechatronics/bev.py b/nrel/hive/model/vehicle/mechatronics/bev.py index d37b36b9..91f70b2c 100644 --- a/nrel/hive/model/vehicle/mechatronics/bev.py +++ b/nrel/hive/model/vehicle/mechatronics/bev.py @@ -151,8 +151,10 @@ def is_full(self, vehicle: Vehicle) -> bool: :param vehicle: :return: """ + battery = vehicle.energy[EnergyType.ELECTRIC] full_kwh = self.battery_capacity_kwh - self.battery_full_threshold_kwh - return vehicle.energy[EnergyType.ELECTRIC] >= full_kwh + is_full = battery >= full_kwh + return is_full def consume_energy(self, vehicle: Vehicle, route: Route) -> Vehicle: """ From 64a761482a435ccf112f1bc5699ad8d075dd6b0b Mon Sep 17 00:00:00 2001 From: rfitzger Date: Thu, 28 Sep 2023 15:32:48 -0600 Subject: [PATCH 7/9] avoid built-in "id" name --- nrel/hive/resources/mock_lobster.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nrel/hive/resources/mock_lobster.py b/nrel/hive/resources/mock_lobster.py index 2738606a..00e65ac5 100644 --- a/nrel/hive/resources/mock_lobster.py +++ b/nrel/hive/resources/mock_lobster.py @@ -341,7 +341,7 @@ def mock_station_from_geoid( env = mock_env() return Station.build( - id=station_id, + station_id=station_id, geoid=geoid, road_network=road_network, chargers=chargers, From f1fd7afe754ccedf092270f47db1fb7e546fc78a Mon Sep 17 00:00:00 2001 From: rfitzger Date: Fri, 29 Sep 2023 11:44:54 -0600 Subject: [PATCH 8/9] out of service instruction --- .../dispatcher/instruction/instructions.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/nrel/hive/dispatcher/instruction/instructions.py b/nrel/hive/dispatcher/instruction/instructions.py index d4129e89..57610e5b 100644 --- a/nrel/hive/dispatcher/instruction/instructions.py +++ b/nrel/hive/dispatcher/instruction/instructions.py @@ -21,6 +21,7 @@ from nrel.hive.state.vehicle_state.dispatch_trip import DispatchTrip from nrel.hive.state.vehicle_state.idle import Idle from nrel.hive.state.vehicle_state.repositioning import Repositioning +from nrel.hive.state.vehicle_state.out_of_service import OutOfService from nrel.hive.state.vehicle_state.reserve_base import ReserveBase from nrel.hive.state.vehicle_state.servicing_pooling_trip import ServicingPoolingTrip from nrel.hive.util.exception import SimulationStateError, InstructionError @@ -341,3 +342,22 @@ def apply_instruction( next_state = ReserveBase.build(self.vehicle_id, self.base_id) return None, InstructionResult(prev_state, next_state) + + +@dataclass(frozen=True) +class OutOfServiceInstruction(Instruction): + vehicle_id: VehicleId + + def apply_instruction( + self, sim_state: SimulationState, env: Environment + ) -> Tuple[Optional[Exception], Optional[InstructionResult]]: + vehicle = sim_state.vehicles.get(self.vehicle_id) + if not vehicle: + msg = ( + f"vehicle {self.vehicle_id} not found; context: applying out of service instruction" + ) + return (SimulationStateError(msg), None) + + prev_state = vehicle.vehicle_state + next_state = OutOfService.build(self.vehicle_id) + return None, InstructionResult(prev_state, next_state) From 4033b3b6ad3c0aa4746a6b785ab338011136056f Mon Sep 17 00:00:00 2001 From: rfitzger Date: Fri, 29 Sep 2023 11:45:05 -0600 Subject: [PATCH 9/9] formatting --- nrel/hive/model/roadnetwork/link_id.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/nrel/hive/model/roadnetwork/link_id.py b/nrel/hive/model/roadnetwork/link_id.py index ae0dc96f..b8df5b73 100644 --- a/nrel/hive/model/roadnetwork/link_id.py +++ b/nrel/hive/model/roadnetwork/link_id.py @@ -45,9 +45,7 @@ def extract_node_ids( return None, (src, dst) -def extract_node_ids_int( - link_id: LinkId -) -> Tuple[Optional[Exception], Optional[Tuple[int, int]]]: +def extract_node_ids_int(link_id: LinkId) -> Tuple[Optional[Exception], Optional[Tuple[int, int]]]: """node ids can be strings for the haversine case but for networkx graphs they must be integers as they are treated as indices. @@ -68,6 +66,7 @@ def extract_node_ids_int( except ValueError as e: return e, None + def reverse_link_id( link_id: LinkId, ) -> Tuple[Optional[Exception], Optional[LinkId]]: