Refactor starting trips -- caller passes in TripInfo. Stop inferring

TripEndpoints from TripLegs. #258

NOW regenerate scenarios. I'm confident this sweeping refactor didn't
break behavior, because prebaked data didn't budge. huge_seattle
scenario went from 147MB to 129MB. Not bad!
This commit is contained in:
Dustin Carlino 2020-11-17 16:59:37 -08:00
parent 8d80668a56
commit 7741ea79b5
5 changed files with 70 additions and 196 deletions

View File

@ -481,36 +481,36 @@
"size_bytes": 9004723
},
"data/system/seattle/scenarios/ballard/weekday.bin": {
"checksum": "f014c2bdce9768f63ab32d24c332dcbe",
"size_bytes": 29686654
"checksum": "b85c1f2649d9f5653a6892530f531bd5",
"size_bytes": 25996430
},
"data/system/seattle/scenarios/downtown/weekday.bin": {
"checksum": "6d7c71d64774b5ae53d17b7e4a494a5a",
"size_bytes": 57831457
"checksum": "c4fa49791d9044953357646547d44c94",
"size_bytes": 46149242
},
"data/system/seattle/scenarios/huge_seattle/weekday.bin": {
"checksum": "de9bedc7ebe58af8f17485ea4a01af49",
"size_bytes": 153841978
"checksum": "838e4da4ecde804e189ae1a723aac875",
"size_bytes": 134353259
},
"data/system/seattle/scenarios/lakeslice/weekday.bin": {
"checksum": "e2037dc1a2059ac9021c0d2b53a53fbb",
"size_bytes": 12677894
"checksum": "ab537ab45dc0696203a7795693d50d75",
"size_bytes": 10936762
},
"data/system/seattle/scenarios/montlake/weekday.bin": {
"checksum": "18e44a3556f382c928e5a35896963133",
"size_bytes": 1762819
"checksum": "56a8d73b8ed7c961399ae1e86ba7d9ba",
"size_bytes": 1536335
},
"data/system/seattle/scenarios/south_seattle/weekday.bin": {
"checksum": "fea36775a87e95fcc810df2faf7be78a",
"size_bytes": 37663645
"checksum": "493bb5cc11b2814e4a3b0fe547b8d356",
"size_bytes": 33451749
},
"data/system/seattle/scenarios/udistrict/weekday.bin": {
"checksum": "0d62a92263ef91b3e9ad36312cd8b9df",
"size_bytes": 13137921
"checksum": "f8fb713f39b4054704560c0c65db2b22",
"size_bytes": 11070560
},
"data/system/seattle/scenarios/west_seattle/weekday.bin": {
"checksum": "e1d0df68c84091ee6e0a6dd22b1235f2",
"size_bytes": 27282051
"checksum": "9ebd16bc8f33a4d539b91ff762c3888d",
"size_bytes": 24859939
},
"data/system/tel_aviv/maps/center.bin": {
"checksum": "d395118f968b001898aba749d20cac02",

View File

@ -3,9 +3,7 @@ use std::collections::HashMap;
use abstutil::{prettyprint_usize, MultiMap, Parallelism, Timer};
use geom::LonLat;
use map_model::{osm, BuildingID, IntersectionID, Map, PathConstraints, PathRequest, PathStep};
use sim::{
IndividTrip, OrigPersonID, PersonID, PersonSpec, Scenario, SpawnTrip, TripEndpoint, TripMode,
};
use sim::{IndividTrip, OrigPersonID, PersonID, PersonSpec, Scenario, TripEndpoint, TripMode};
use crate::soundcast::popdat::{Endpoint, OrigTrip, PopDat};
@ -244,36 +242,23 @@ pub fn make_weekday_scenario(
huge_map: &Map,
timer: &mut Timer,
) -> Scenario {
let trips = clip_trips(map, popdat, huge_map, timer);
let orig_trips = trips.len();
let mut individ_trips: Vec<Option<IndividTrip>> = Vec::new();
// person -> (trip seq, index into individ_trips)
let mut trips_per_person: MultiMap<OrigPersonID, ((usize, bool, usize), usize)> =
MultiMap::new();
for (trip, depart, person, seq, purpose) in timer.parallelize(
"turn Soundcast trips into SpawnTrips",
Parallelism::Polite,
trips,
|trip| {
(
SpawnTrip::new(trip.from, trip.to, trip.orig.mode, map),
trip.orig.depart_at,
trip.orig.person,
trip.orig.seq,
trip.orig.purpose,
)
},
) {
if let Some(trip) = trip {
let idx = individ_trips.len();
individ_trips.push(Some(IndividTrip::new(depart, purpose, trip)));
trips_per_person.insert(person, (seq, idx));
}
for trip in clip_trips(map, popdat, huge_map, timer) {
let idx = individ_trips.len();
individ_trips.push(Some(IndividTrip::new(
trip.orig.depart_at,
trip.orig.purpose,
trip.from,
trip.to,
trip.orig.mode,
)));
trips_per_person.insert(trip.orig.person, (trip.orig.seq, idx));
}
timer.note(format!(
"{} clipped trips down to {}, over {} people",
prettyprint_usize(orig_trips),
"{} clipped trips, over {} people",
prettyprint_usize(individ_trips.len()),
prettyprint_usize(trips_per_person.len())
));
@ -307,5 +292,5 @@ pub fn make_weekday_scenario(
people,
only_seed_buses: None,
}
.remove_weird_schedules(map)
.remove_weird_schedules()
}

View File

@ -16,7 +16,7 @@ use map_model::{
use crate::make::fork_rng;
use crate::{
CarID, DrivingGoal, OrigPersonID, ParkingSpot, PersonID, SidewalkSpot, Sim, TripEndpoint,
TripMode, TripSpawner, TripSpec, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH,
TripInfo, TripMode, TripSpawner, TripSpec, Vehicle, VehicleSpec, VehicleType, BIKE_LENGTH,
MAX_CAR_LENGTH, MIN_CAR_LENGTH, SPAWN_DIST,
};
@ -210,13 +210,21 @@ impl Scenario {
};
schedule_trips.push((
person.id,
t.depart,
spec,
t.from.clone(),
t.purpose,
t.cancelled,
t.modified,
map,
TripInfo {
departure: t.depart,
mode: t.mode,
start: t.from.clone(),
end: t.to.clone(),
purpose: t.purpose,
modified: t.modified,
capped: false,
cancellation_reason: if t.cancelled {
Some(format!("cancelled by ScenarioModifier"))
} else {
None
},
},
));
}
}
@ -226,11 +234,7 @@ impl Scenario {
"schedule trips",
Parallelism::Fastest,
schedule_trips,
|tuple| {
spawner.schedule_trip(
tuple.0, tuple.1, tuple.2, tuple.3, tuple.4, tuple.5, tuple.6, tuple.7,
)
},
|tuple| spawner.schedule_trip(tuple.0, tuple.1, tuple.2, map),
);
spawner.schedule_trips(results);

View File

@ -4,12 +4,11 @@
use serde::{Deserialize, Serialize};
use abstutil::Timer;
use geom::Time;
use map_model::{BuildingID, BusRouteID, BusStopID, Map, PathConstraints, PathRequest, Position};
use crate::{
CarID, Command, DrivingGoal, PersonID, Scheduler, SidewalkSpot, TripEndpoint, TripLeg,
TripManager, TripMode, TripPurpose, VehicleType,
CarID, Command, DrivingGoal, PersonID, Scheduler, SidewalkSpot, TripInfo, TripLeg, TripManager,
VehicleType,
};
// TODO Some of these fields are unused now that we separately pass TripEndpoint
@ -52,15 +51,7 @@ pub enum TripSpec {
},
}
type TripSpawnPlan = (
PersonID,
Time,
TripSpec,
TripEndpoint,
TripPurpose,
bool,
bool,
);
type TripSpawnPlan = (PersonID, TripSpec, TripInfo);
/// This structure is created temporarily by a Scenario or to interactively spawn agents.
pub struct TripSpawner {
@ -77,12 +68,8 @@ impl TripSpawner {
pub fn schedule_trip(
&self,
person: PersonID,
start_time: Time,
mut spec: TripSpec,
trip_start: TripEndpoint,
purpose: TripPurpose,
cancelled: bool,
modified: bool,
info: TripInfo,
map: &Map,
) -> TripSpawnPlan {
// TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
@ -179,9 +166,7 @@ impl TripSpawner {
TripSpec::UsingTransit { .. } => {}
};
(
person, start_time, spec, trip_start, purpose, cancelled, modified,
)
(person, spec, info)
}
pub fn schedule_trips(&mut self, trips: Vec<TripSpawnPlan>) {
@ -196,13 +181,14 @@ impl TripSpawner {
timer: &mut Timer,
) {
timer.start_iter("spawn trips", self.trips.len());
for (p, start_time, spec, trip_start, purpose, cancelled, modified) in self.trips.drain(..)
{
for (p, spec, info) in self.trips.drain(..) {
timer.next();
// TODO clone() is super weird to do here, but we just need to make the borrow checker
// happy. All we're doing is grabbing IDs off this.
let person = trips.get_person(p).unwrap().clone();
let departure = info.departure;
let cancellation_reason = info.cancellation_reason.clone();
// Just create the trip for each case.
// TODO Not happy about this clone()
let trip = match spec.clone() {
@ -213,42 +199,13 @@ impl TripSpawner {
if let DrivingGoal::ParkNear(b) = goal {
legs.push(TripLeg::Walk(SidewalkSpot::building(b, map)));
}
trips.new_trip(
person.id,
start_time,
trip_start,
if use_vehicle.1 == VehicleType::Bike {
TripMode::Bike
} else {
TripMode::Drive
},
purpose,
modified,
legs,
map,
)
trips.new_trip(person.id, info, legs)
}
TripSpec::SpawningFailure { use_vehicle, .. } => {
// TODO Need to plumb TripInfo into here
todo!()
/*let mut legs = vec![TripLeg::Drive(use_vehicle, goal.clone())];
if let DrivingGoal::ParkNear(b) = goal {
legs.push(TripLeg::Walk(SidewalkSpot::building(b, map)));
}
trips.new_trip(
person.id,
start_time,
trip_start,
if use_vehicle.1 == VehicleType::Bike {
TripMode::Bike
} else {
TripMode::Drive
},
purpose,
modified,
legs,
map,
)*/
TripSpec::SpawningFailure { .. } => {
// TODO Is it OK to have empty trip legs?
// TODO Do we have to cancel the trip or move the vehicle here?
let legs = Vec::new();
trips.new_trip(person.id, info, legs)
}
TripSpec::UsingParkedCar { car, goal, .. } => {
let mut legs = vec![
@ -261,27 +218,11 @@ impl TripSpawner {
}
DrivingGoal::Border(_, _) => {}
}
trips.new_trip(
person.id,
start_time,
trip_start,
TripMode::Drive,
purpose,
modified,
legs,
map,
)
trips.new_trip(person.id, info, legs)
}
TripSpec::JustWalking { goal, .. } => {
trips.new_trip(person.id, info, vec![TripLeg::Walk(goal.clone())])
}
TripSpec::JustWalking { goal, .. } => trips.new_trip(
person.id,
start_time,
trip_start,
TripMode::Walk,
purpose,
modified,
vec![TripLeg::Walk(goal.clone())],
map,
),
TripSpec::UsingBike { bike, start, goal } => {
let walk_to = SidewalkSpot::bike_rack(start, map).unwrap();
let mut legs = vec![
@ -294,16 +235,7 @@ impl TripSpawner {
}
DrivingGoal::Border(_, _) => {}
};
trips.new_trip(
person.id,
start_time,
trip_start,
TripMode::Bike,
purpose,
modified,
legs,
map,
)
trips.new_trip(person.id, info, legs)
}
TripSpec::UsingTransit {
route,
@ -325,26 +257,14 @@ impl TripSpawner {
TripLeg::RideBus(route, None),
]
};
trips.new_trip(
person.id,
start_time,
trip_start,
TripMode::Transit,
purpose,
modified,
legs,
map,
)
trips.new_trip(person.id, info, legs)
}
};
if cancelled {
trips.cancel_unstarted_trip(
trip,
format!("traffic pattern modifier cancelled this trip"),
);
if let Some(msg) = cancellation_reason {
trips.cancel_unstarted_trip(trip, msg);
} else {
scheduler.push(start_time, Command::StartTrip(trip, spec));
scheduler.push(departure, Command::StartTrip(trip, spec));
}
}
}

View File

@ -87,49 +87,14 @@ impl TripManager {
id
}
pub fn new_trip(
&mut self,
person: PersonID,
departure: Time,
start: TripEndpoint,
mode: TripMode,
purpose: TripPurpose,
modified: bool,
legs: Vec<TripLeg>,
map: &Map,
) -> TripID {
pub fn new_trip(&mut self, person: PersonID, info: TripInfo, legs: Vec<TripLeg>) -> TripID {
assert!(!legs.is_empty());
// TODO Make sure the legs constitute a valid state machine.
let id = TripID(self.trips.len());
let end = match legs.last() {
Some(TripLeg::Walk(ref spot)) => match spot.connection {
SidewalkPOI::Building(b) => TripEndpoint::Bldg(b),
SidewalkPOI::Border(i) => TripEndpoint::Border(i),
_ => unreachable!(),
},
Some(TripLeg::Drive(_, ref goal)) => match goal {
DrivingGoal::ParkNear(b) => TripEndpoint::Bldg(*b),
DrivingGoal::Border(i, _) => TripEndpoint::Border(*i),
},
Some(TripLeg::RideBus(r, ref maybe_stop2)) => {
assert!(maybe_stop2.is_none());
TripEndpoint::Border(map.get_l(map.get_br(*r).end_border.unwrap()).dst_i)
}
_ => unreachable!(),
};
let trip = Trip {
id,
info: TripInfo {
departure,
mode,
start,
end,
purpose,
modified,
capped: false,
cancellation_reason: None,
},
info,
person,
started: false,
finished_at: None,