Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes for handling LinkIds #211

Merged
merged 9 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions nrel/hive/dispatcher/instruction/instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
28 changes: 24 additions & 4 deletions nrel/hive/model/roadnetwork/link_id.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
from ast import literal_eval
from typing import Optional, Tuple, Any

from nrel.hive.util.typealiases import LinkId

NodeId = Any
Expand Down Expand Up @@ -39,14 +37,36 @@ 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

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]]:
Expand Down
10 changes: 7 additions & 3 deletions nrel/hive/model/roadnetwork/osm/osm_roadnetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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.")

Expand All @@ -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):
Expand Down Expand Up @@ -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
)
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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()
Expand Down
12 changes: 6 additions & 6 deletions nrel/hive/model/station/station.py
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down Expand Up @@ -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
Expand All @@ -114,20 +114,20 @@ 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})
position = road_network.position_from_geoid(geoid)
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,
Expand Down Expand Up @@ -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}),
Expand Down
4 changes: 3 additions & 1 deletion nrel/hive/model/vehicle/mechatronics/bev.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand Down
2 changes: 1 addition & 1 deletion nrel/hive/resources/mock_lobster.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down