Skip to content

Commit

Permalink
Merge pull request #1466 from AisenGinn/iss1435
Browse files Browse the repository at this point in the history
Single vehicle in traffic
  • Loading branch information
Gamenot authored Nov 17, 2022
2 parents c4f76d8 + 7129e8e commit 748171a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Copy and pasting the git commit messages is __NOT__ enough.

## [Unreleased]
### Added
- Added single vehicle `Trip` into type.
### Deprecated
### Changed
### Removed
Expand Down
47 changes: 45 additions & 2 deletions smarts/sstudio/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,17 @@ def _writexml(
):
# Actors and routes may be declared once then reused. To prevent creating
# duplicates we unique them here.
for actor in {
actors_for_vtypes = {
actor for flow in traffic.flows for actor in flow.actors.keys()
}:
}
if traffic.trips:
actors_for_vtypes |= {trip.actor for trip in traffic.trips}
vehicle_id_set = {trip.vehicle_name for trip in traffic.trips}
vehilce_ids_list = [trip.vehicle_name for trip in traffic.trips]
if len(vehicle_id_set) != len(vehilce_ids_list):
raise ValueError("Repeated single vehicle names is not allowed.")

for actor in actors_for_vtypes:
sigma = min(1, max(0, actor.imperfection.sample())) # range [0,1]
min_gap = max(0, actor.min_gap.sample()) # range >= 0
doc.stag(
Expand Down Expand Up @@ -281,6 +289,9 @@ def _writexml(
end=flow.end,
**rate_option,
)
# write trip into xml format
if traffic.trips:
self.write_trip_xml(traffic, doc, fill_in_route_gaps)

with open(route_path, "w") as f:
f.write(
Expand All @@ -289,6 +300,38 @@ def _writexml(
)
)

def write_trip_xml(self, traffic, doc, fill_in_gaps):
"""Writes a trip spec into a route file. Typically this would be the source
data to SUMO's DUAROUTER.
"""
# Make sure all routes are "resolved" (e.g. `RandomRoute` are converted to
# `Route`) so that we can write them all to file.
resolved_routes = {}
for route in {trip.route for trip in traffic.trips}:
resolved_routes[route] = self.resolve_route(route, fill_in_gaps)

for route in set(resolved_routes.values()):
doc.stag("route", id=route.id + "trip", edges=" ".join(route.roads))

# We don't de-dup flows since defining the same flow multiple times should
# create multiple traffic flows. Since IDs can't be reused, we also unique
# them here.
for trip_idx, trip in enumerate(traffic.trips):
route = resolved_routes[trip.route]
actor = trip.actor
doc.stag(
"vehicle",
id="{}".format(trip.vehicle_name),
type=actor.id,
route=route.id,
depart=trip.depart,
departLane=route.begin[1],
departPos=route.begin[2],
departSpeed=actor.depart_speed,
arrivalLane=route.end[1],
arrivalPos=route.end[2],
)

def _cache_road_network(self):
if not self._road_network:
from smarts.core.sumo_road_network import SumoRoadNetwork
Expand Down
38 changes: 38 additions & 0 deletions smarts/sstudio/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,42 @@ def __eq__(self, other):
return self.__class__ == other.__class__ and hash(self) == hash(other)


@dataclass(frozen=True)
class Trip:
"""A route with a single actor type with name and unique id."""

vehicle_name: str
"""The name of the vehicle. It must be unique. """
route: Union[RandomRoute, Route]
"""The route for the actor to attempt to follow."""
vehicle_type: str = "passenger"
"""The type of the vehicle"""
depart: float = 0
"""Start time in seconds."""
actor: TrafficActor = field(init=False)
"""The traffic actor model (usually vehicle) that will be used for the trip."""

def __post_init__(self):
object.__setattr__(
self,
"actor",
TrafficActor(name=self.vehicle_name, vehicle_type=self.vehicle_type),
)

@property
def id(self) -> str:
"""The unique id of this trip."""
return self.vehicle_name

def __hash__(self):
# Custom hash since self.actors is not hashable, here we first convert to a
# frozenset.
return _pickle_hash((self.route, self.actor))

def __eq__(self, other):
return self.__class__ == other.__class__ and hash(self) == hash(other)


@dataclass(frozen=True)
class JunctionEdgeIDResolver:
"""A utility for resolving a junction connection edge"""
Expand Down Expand Up @@ -547,6 +583,8 @@ class Traffic:
"""Flows are used to define a steady supply of vehicles."""
# TODO: consider moving TrafficHistory stuff in here (and rename to Trajectory)
# TODO: - treat history points like Vias (no guarantee on history timesteps anyway)
trips: Optional[Sequence[Trip]] = None
"""Trips are used to define a series of single vehicle trip."""
engine: str = "SUMO"
"""The traffic-generation engine to use. Supported values include: SUMO, SMARTS. SUMO requires using a SumoRoadNetwork for the RoadMap."""

Expand Down

0 comments on commit 748171a

Please sign in to comment.