plumb more info in sim events. this will allow for some consolidated pandemic modeling

This commit is contained in:
Dustin Carlino 2020-04-02 15:12:46 -07:00
parent c12775e5ea
commit 29c86d656d
10 changed files with 96 additions and 61 deletions

View File

@ -163,8 +163,8 @@ fn make_timeline(
TripPhaseType::Walking => Color::hex("#DF8C3D"),
TripPhaseType::Biking => app.cs.get("bike lane"),
TripPhaseType::Parking => Color::hex("#4E30A6"),
TripPhaseType::WaitingForBus(_) => app.cs.get("bus stop marking"),
TripPhaseType::RidingBus(_) => app.cs.get("bus lane"),
TripPhaseType::WaitingForBus(_, _) => app.cs.get("bus stop marking"),
TripPhaseType::RidingBus(_, _) => app.cs.get("bus lane"),
TripPhaseType::Aborted | TripPhaseType::Finished => unreachable!(),
}
.alpha(0.7);
@ -215,10 +215,10 @@ fn make_timeline(
TripPhaseType::Walking => "../data/system/assets/timeline/walking.svg",
TripPhaseType::Biking => "../data/system/assets/timeline/biking.svg",
TripPhaseType::Parking => "../data/system/assets/timeline/parking.svg",
TripPhaseType::WaitingForBus(_) => {
TripPhaseType::WaitingForBus(_, _) => {
"../data/system/assets/timeline/waiting_for_bus.svg"
}
TripPhaseType::RidingBus(_) => "../data/system/assets/timeline/riding_bus.svg",
TripPhaseType::RidingBus(_, _) => "../data/system/assets/timeline/riding_bus.svg",
TripPhaseType::Aborted | TripPhaseType::Finished => unreachable!(),
},
// TODO Hardcoded layouting...

View File

@ -111,12 +111,14 @@ impl Analytics {
}
// Bus passengers
if let Event::PedReachedBusStop(_, stop, route) = ev {
self.bus_passengers_waiting.push((time, stop, route));
if let Event::TripPhaseStarting(_, _, _, _, ref tpt) = ev {
if let TripPhaseType::WaitingForBus(route, stop) = tpt {
self.bus_passengers_waiting.push((time, *stop, *route));
}
}
// Started trips
if let Event::TripPhaseStarting(id, mode, _, _) = ev {
if let Event::TripPhaseStarting(id, _, mode, _, _) = ev {
// TODO More efficiently
if !self.started_trips.contains_key(&id)
&& !self
@ -148,7 +150,7 @@ impl Analytics {
// TODO Kinda hacky, but these all consume the event, so kinda bundle em.
match ev {
Event::TripPhaseStarting(id, _, maybe_req, phase_type) => {
Event::TripPhaseStarting(id, _, _, maybe_req, phase_type) => {
self.trip_log.push((time, id, maybe_req, phase_type));
}
Event::TripAborted(id, _) => {

View File

@ -16,15 +16,11 @@ pub enum Event {
BusArrivedAtStop(CarID, BusRouteID, BusStopID),
BusDepartedFromStop(CarID, BusRouteID, BusStopID),
PedEntersBus(PedestrianID, CarID, BusRouteID),
PedLeavesBus(PedestrianID, CarID, BusRouteID),
PersonEntersBuilding(PersonID, BuildingID),
PersonLeavesBuilding(PersonID, BuildingID),
PedReachedParkingSpot(PedestrianID, ParkingSpot),
PedReachedBorder(PedestrianID, IntersectionID),
PedReachedBusStop(PedestrianID, BusStopID, BusRouteID),
BikeStoppedAtSidewalk(CarID, LaneID),
@ -33,7 +29,13 @@ pub enum Event {
TripFinished(TripID, TripMode, Duration),
TripAborted(TripID, TripMode),
TripPhaseStarting(TripID, TripMode, Option<PathRequest>, TripPhaseType),
TripPhaseStarting(
TripID,
PersonID,
TripMode,
Option<PathRequest>,
TripPhaseType,
),
// Just use for parking replanning. Not happy about copying the full path in here, but the way
// to plumb info into Analytics is Event.
@ -46,8 +48,8 @@ pub enum TripPhaseType {
Walking,
Biking,
Parking,
WaitingForBus(BusRouteID),
RidingBus(BusRouteID),
WaitingForBus(BusRouteID, BusStopID),
RidingBus(BusRouteID, CarID),
Aborted,
Finished,
}
@ -59,8 +61,8 @@ impl TripPhaseType {
TripPhaseType::Walking => "walking".to_string(),
TripPhaseType::Biking => "biking".to_string(),
TripPhaseType::Parking => "parking".to_string(),
TripPhaseType::WaitingForBus(r) => format!("waiting for bus {}", map.get_br(r).name),
TripPhaseType::RidingBus(r) => format!("riding bus {}", map.get_br(r).name),
TripPhaseType::WaitingForBus(r, _) => format!("waiting for bus {}", map.get_br(r).name),
TripPhaseType::RidingBus(r, _) => format!("riding bus {}", map.get_br(r).name),
TripPhaseType::Aborted => "trip aborted due to some bug".to_string(),
TripPhaseType::Finished => "trip finished".to_string(),
}

View File

@ -11,7 +11,8 @@ mod transit;
mod trips;
pub use self::analytics::{Analytics, TripPhase};
pub use self::events::{Event, TripPhaseType};
pub(crate) use self::events::Event;
pub use self::events::TripPhaseType;
pub use self::make::{
ABTest, BorderSpawnOverTime, IndividTrip, OriginDestination, PersonSpec, Scenario,
ScenarioGenerator, SeedParkedCars, SimFlags, SpawnOverTime, SpawnTrip, TripSpawner, TripSpec,
@ -490,8 +491,7 @@ pub struct CreateCar {
pub start_dist: Distance,
pub maybe_parked_car: Option<ParkedCar>,
// None for buses
pub trip: Option<TripID>,
pub person: Option<PersonID>,
pub trip_and_person: Option<(TripID, PersonID)>,
}
impl CreateCar {
@ -509,8 +509,7 @@ impl CreateCar {
req,
start_dist: start_pos.dist_along(),
maybe_parked_car: None,
trip: Some(trip),
person: Some(person),
trip_and_person: Some((trip, person)),
}
}
@ -529,8 +528,7 @@ impl CreateCar {
req,
start_dist,
maybe_parked_car: Some(parked_car),
trip: Some(trip),
person: Some(person),
trip_and_person: Some((trip, person)),
}
}
}

View File

@ -13,8 +13,7 @@ pub struct Car {
pub state: CarState,
pub router: Router,
// None for buses
pub trip: Option<TripID>,
pub person: Option<PersonID>,
pub trip_and_person: Option<(TripID, PersonID)>,
pub started_at: Time,
pub total_blocked_time: Duration,

View File

@ -97,8 +97,7 @@ impl DrivingSimState {
last_steps: VecDeque::new(),
started_at: now,
total_blocked_time: Duration::ZERO,
trip: params.trip,
person: params.person,
trip_and_person: params.trip_and_person,
};
if let Some(p) = params.maybe_parked_car {
car.state = CarState::Unparking(
@ -114,7 +113,7 @@ impl DrivingSimState {
&car.vehicle,
parking,
map,
car.trip,
car.trip_and_person,
&mut self.events,
) {
None | Some(ActionAtEnd::GotoLaneEnd) => {}
@ -275,7 +274,7 @@ impl DrivingSimState {
&car.vehicle,
parking,
map,
car.trip,
car.trip_and_person,
&mut self.events,
);
}
@ -365,9 +364,13 @@ impl DrivingSimState {
// We do NOT need to update the follower. If they were Queued, they'll remain that
// way, until laggy_head is None.
let last_step =
car.router
.advance(&car.vehicle, parking, map, car.trip, &mut self.events);
let last_step = car.router.advance(
&car.vehicle,
parking,
map,
car.trip_and_person,
&mut self.events,
);
car.total_blocked_time += now - blocked_since;
car.state = car.crossing_state(Distance::ZERO, now, map);
scheduler.push(car.state.get_end_time(), Command::UpdateCar(car.vehicle.id));
@ -442,7 +445,7 @@ impl DrivingSimState {
&car.vehicle,
parking,
map,
car.trip,
car.trip_and_person,
&mut self.events,
) {
Some(ActionAtEnd::VanishAtBorder(i)) => {
@ -783,7 +786,7 @@ impl DrivingSimState {
result.push(UnzoomedAgent {
vehicle_type: Some(car.vehicle.vehicle_type),
pos: queue.id.dist_along(dist, map).0,
person: car.person,
person: car.trip_and_person.map(|(_, p)| p),
});
}
}
@ -804,7 +807,7 @@ impl DrivingSimState {
for (car, dist) in
queue.get_car_positions(trip_positions.time, &self.cars, &self.queues)
{
if let Some(trip) = self.cars[&car].trip {
if let Some((trip, _)) = self.cars[&car].trip_and_person {
trip_positions
.canonical_pt_per_trip
.insert(trip, queue.id.dist_along(dist, map).0);

View File

@ -1,6 +1,7 @@
use crate::mechanics::Queue;
use crate::{
Event, ParkingSimState, ParkingSpot, SidewalkSpot, TripID, TripMode, TripPhaseType, Vehicle,
Event, ParkingSimState, ParkingSpot, PersonID, SidewalkSpot, TripID, TripMode, TripPhaseType,
Vehicle,
};
use geom::Distance;
use map_model::{
@ -127,13 +128,20 @@ impl Router {
vehicle: &Vehicle,
parking: &ParkingSimState,
map: &Map,
trip: Option<TripID>,
trip_and_person: Option<(TripID, PersonID)>,
events: &mut Vec<Event>,
) -> Traversable {
let prev = self.path.shift(map).as_traversable();
if self.last_step() {
// Do this to trigger the side-effect of looking for parking.
self.maybe_handle_end(Distance::ZERO, vehicle, parking, map, trip, events);
self.maybe_handle_end(
Distance::ZERO,
vehicle,
parking,
map,
trip_and_person,
events,
);
}
// Sanity check laws haven't been broken
@ -159,7 +167,7 @@ impl Router {
parking: &ParkingSimState,
map: &Map,
// TODO Not so nice to plumb all of this here
trip: Option<TripID>,
trip_and_person: Option<(TripID, PersonID)>,
events: &mut Vec<Event>,
) -> Option<ActionAtEnd> {
match self.goal {
@ -194,9 +202,10 @@ impl Router {
vehicle,
map,
) {
if let Some(t) = trip {
if let Some((t, p)) = trip_and_person {
events.push(Event::TripPhaseStarting(
t,
p,
TripMode::Drive,
Some(PathRequest {
start: Position::new(current_lane, front),
@ -217,9 +226,10 @@ impl Router {
}
events.push(Event::PathAmended(self.path.clone()));
// TODO This path might not be the same as the one found here...
if let Some(t) = trip {
if let Some((t, p)) = trip_and_person {
events.push(Event::TripPhaseStarting(
t,
p,
TripMode::Drive,
Some(PathRequest {
start: Position::new(current_lane, front),

View File

@ -269,8 +269,7 @@ impl Sim {
req: req.clone(),
router: Router::follow_bus_route(path.clone(), end_dist),
maybe_parked_car: None,
trip: None,
person: None,
trip_and_person: None,
},
map,
&self.intersections,
@ -409,7 +408,7 @@ impl Sim {
&self.parking,
&mut self.scheduler,
) {
if let Some(trip) = create_car.trip {
if let Some((trip, _)) = create_car.trip_and_person {
self.trips
.agent_starting_trip_leg(AgentID::Car(create_car.vehicle.id), trip);
}
@ -417,15 +416,16 @@ impl Sim {
if let ParkingSpot::Offstreet(b, _) = parked_car.spot {
// Buses don't start in parking garages, so trip must exist
events.push(Event::PersonLeavesBuilding(
self.trip_to_person(create_car.trip.unwrap()),
create_car.trip_and_person.unwrap().1,
b,
));
}
self.parking.remove_parked_car(parked_car);
}
if let Some(trip) = create_car.trip {
if let Some((trip, person)) = create_car.trip_and_person {
events.push(Event::TripPhaseStarting(
trip,
person,
// TODO sketchy...
if create_car.vehicle.id.1 == VehicleType::Car {
TripMode::Drive
@ -449,7 +449,7 @@ impl Sim {
Command::SpawnCar(create_car, retry_if_no_room),
);
} else {
if let Some(trip) = create_car.trip {
if let Some((trip, _)) = create_car.trip_and_person {
println!("No room to spawn car for {}. Not retrying!", trip);
self.trips.abort_trip_failed_start(trip);
} else {
@ -518,6 +518,7 @@ impl Sim {
);
events.push(Event::TripPhaseStarting(
create_ped.trip,
create_ped.person,
TripMode::Walk,
Some(create_ped.req.clone()),
TripPhaseType::Walking,

View File

@ -1,6 +1,6 @@
use crate::{
CarID, Event, PedestrianID, Router, Scheduler, TripManager, TripMode, TripPhaseType,
WalkingSimState,
CarID, Event, PedestrianID, PersonID, Router, Scheduler, TripID, TripManager, TripMode,
TripPhaseType, WalkingSimState,
};
use abstutil::{deserialize_btreemap, serialize_btreemap};
use geom::{Distance, Time};
@ -168,7 +168,6 @@ impl TransitSimState {
let mut still_riding = Vec::new();
for (ped, stop2) in bus.passengers.drain(..) {
if stop1 == stop2 {
self.events.push(Event::PedLeavesBus(ped, id, bus.route));
trips.ped_left_bus(now, ped, map, scheduler);
} else {
still_riding.push((ped, stop2));
@ -183,17 +182,17 @@ impl TransitSimState {
{
if bus.route == route {
bus.passengers.push((ped, stop2));
self.events.push(Event::PedEntersBus(ped, id, route));
let trip = trips.ped_boarded_bus(now, ped, walking);
let (trip, person) = trips.ped_boarded_bus(now, ped, walking);
self.events.push(Event::TripPhaseStarting(
trip,
person,
TripMode::Transit,
Some(PathRequest {
start: map.get_bs(stop1).driving_pos,
end: map.get_bs(stop2).driving_pos,
constraints: PathConstraints::Bus,
}),
TripPhaseType::RidingBus(route),
TripPhaseType::RidingBus(route, bus.car),
));
} else {
still_waiting.push((ped, route, stop2, started_waiting));
@ -229,9 +228,12 @@ impl TransitSimState {
&mut self,
now: Time,
ped: PedestrianID,
trip: TripID,
person: PersonID,
stop1: BusStopID,
route_id: BusRouteID,
stop2: BusStopID,
map: &Map,
) -> bool {
assert!(stop1 != stop2);
if let Some(route) = self.routes.get(&route_id) {
@ -243,8 +245,17 @@ impl TransitSimState {
.unwrap()
.passengers
.push((ped, stop2));
// TODO shift trips
self.events.push(Event::PedEntersBus(ped, *bus, route_id));
self.events.push(Event::TripPhaseStarting(
trip,
person,
TripMode::Transit,
Some(PathRequest {
start: map.get_bs(stop1).driving_pos,
end: map.get_bs(stop2).driving_pos,
constraints: PathConstraints::Bus,
}),
TripPhaseType::RidingBus(route_id, *bus),
));
return true;
}
}

View File

@ -390,14 +390,23 @@ impl TripManager {
}
match trip.legs[1] {
TripLeg::RideBus(_, route, stop2) => {
self.events.push(Event::PedReachedBusStop(ped, stop, route));
self.events.push(Event::TripPhaseStarting(
trip.id,
trip.person,
trip.mode,
None,
TripPhaseType::WaitingForBus(route),
TripPhaseType::WaitingForBus(route, stop),
));
if transit.ped_waiting_for_bus(now, ped, stop, route, stop2) {
if transit.ped_waiting_for_bus(
now,
ped,
trip.id,
trip.person,
stop,
route,
stop2,
map,
) {
trip.legs.pop_front();
None
} else {
@ -413,12 +422,12 @@ impl TripManager {
now: Time,
ped: PedestrianID,
walking: &mut WalkingSimState,
) -> TripID {
) -> (TripID, PersonID) {
// TODO Make sure canonical pt is the bus while the ped is riding it
let trip = &mut self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0];
trip.legs.pop_front();
walking.ped_boarded_bus(now, ped);
trip.id
(trip.id, trip.person)
}
pub fn ped_left_bus(