1 use crate::analytics::Window; 2 use crate::{ 3 AgentID, AgentType, AlertLocation, Analytics, CapSimState, CarID, Command, CreateCar, 4 DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, DrivingSimState, Event, GetDrawAgents, 5 IntersectionSimState, OrigPersonID, PandemicModel, ParkedCar, ParkingSimState, ParkingSpot, 6 PedestrianID, Person, PersonID, PersonState, Router, Scenario, Scheduler, SidewalkPOI, 7 SidewalkSpot, TransitSimState, TripID, TripInfo, TripManager, TripPhaseType, TripResult, 8 TripSpawner, UnzoomedAgent, Vehicle, VehicleSpec, VehicleType, WalkingSimState, BUS_LENGTH, 9 LIGHT_RAIL_LENGTH, MIN_CAR_LENGTH, SPAWN_DIST, 10 }; 11 use abstutil::{prettyprint_usize, serialized_size_bytes, Counter, Parallelism, Timer}; 12 use geom::{Distance, Duration, PolyLine, Pt2D, Speed, Time}; 13 use instant::Instant; 14 use map_model::{ 15 BuildingID, BusRoute, BusRouteID, BusStopID, IntersectionID, Lane, LaneID, Map, ParkingLotID, 16 Path, PathConstraints, PathRequest, Position, RoadID, Traversable, 17 }; 18 use rand_xorshift::XorShiftRng; 19 use serde::{Deserialize, Serialize}; 20 use std::collections::{BTreeMap, HashSet}; 21 use std::panic; 22 23 // TODO Do something else. 24 const BLIND_RETRY_TO_SPAWN: Duration = Duration::const_seconds(5.0); 25 26 #[derive(Serialize, Deserialize, Clone)] 27 pub struct Sim { 28 driving: DrivingSimState, 29 parking: ParkingSimState, 30 walking: WalkingSimState, 31 intersections: IntersectionSimState, 32 transit: TransitSimState, 33 cap: CapSimState, 34 trips: TripManager, 35 #[serde(skip_serializing, skip_deserializing)] 36 pandemic: Option<PandemicModel>, 37 scheduler: Scheduler, 38 time: Time, 39 40 // TODO Reconsider these 41 pub(crate) map_name: String, 42 pub(crate) edits_name: String, 43 // Some tests deliberately set different scenario names for comparisons. 44 // TODO Maybe get rid of this, now that savestates aren't used 45 run_name: String, 46 step_count: usize, 47 48 // Don't serialize, to reduce prebaked savestate size. Analytics are saved once covering the 49 // full day and can be trimmed to any time. 50 #[serde(skip_serializing, skip_deserializing)] 51 analytics: Analytics, 52 53 #[serde(skip_serializing, skip_deserializing)] 54 alerts: AlertHandler, 55 } 56 57 pub struct Ctx<'a> { 58 pub parking: &'a mut ParkingSimState, 59 pub intersections: &'a mut IntersectionSimState, 60 pub cap: &'a mut CapSimState, 61 pub scheduler: &'a mut Scheduler, 62 pub map: &'a Map, 63 } 64 65 #[derive(Clone)] 66 pub struct SimOptions { 67 pub run_name: String, 68 pub use_freeform_policy_everywhere: bool, 69 pub dont_block_the_box: bool, 70 pub recalc_lanechanging: bool, 71 pub break_turn_conflict_cycles: bool, 72 pub handle_uber_turns: bool, 73 pub enable_pandemic_model: Option<XorShiftRng>, 74 pub alerts: AlertHandler, 75 pub pathfinding_upfront: bool, 76 } 77 78 #[derive(Clone)] 79 pub enum AlertHandler { 80 // Just print the alert to STDOUT 81 Print, 82 // Print the alert to STDOUT and don't proceed until the UI calls clear_alerts() 83 Block, 84 // Don't do anything 85 Silence, 86 } 87 88 impl std::default::Default for AlertHandler { default() -> AlertHandler89 fn default() -> AlertHandler { 90 AlertHandler::Print 91 } 92 } 93 94 impl SimOptions { new(run_name: &str) -> SimOptions95 pub fn new(run_name: &str) -> SimOptions { 96 SimOptions { 97 run_name: run_name.to_string(), 98 use_freeform_policy_everywhere: false, 99 dont_block_the_box: true, 100 recalc_lanechanging: true, 101 break_turn_conflict_cycles: true, 102 handle_uber_turns: true, 103 enable_pandemic_model: None, 104 alerts: AlertHandler::Print, 105 pathfinding_upfront: false, 106 } 107 } 108 } 109 110 // Setup 111 impl Sim { new(map: &Map, opts: SimOptions, timer: &mut Timer) -> Sim112 pub fn new(map: &Map, opts: SimOptions, timer: &mut Timer) -> Sim { 113 let mut scheduler = Scheduler::new(); 114 Sim { 115 driving: DrivingSimState::new(map, opts.recalc_lanechanging, opts.handle_uber_turns), 116 parking: ParkingSimState::new(map, timer), 117 walking: WalkingSimState::new(), 118 intersections: IntersectionSimState::new( 119 map, 120 &mut scheduler, 121 opts.use_freeform_policy_everywhere, 122 opts.dont_block_the_box, 123 opts.break_turn_conflict_cycles, 124 opts.handle_uber_turns, 125 ), 126 transit: TransitSimState::new(map), 127 cap: CapSimState::new(map), 128 trips: TripManager::new(opts.pathfinding_upfront), 129 pandemic: if let Some(rng) = opts.enable_pandemic_model { 130 Some(PandemicModel::new(rng)) 131 } else { 132 None 133 }, 134 scheduler, 135 time: Time::START_OF_DAY, 136 137 map_name: map.get_name().to_string(), 138 // TODO 139 edits_name: "untitled edits".to_string(), 140 run_name: opts.run_name, 141 step_count: 0, 142 alerts: opts.alerts, 143 144 analytics: Analytics::new(), 145 } 146 } 147 make_spawner(&self) -> TripSpawner148 pub fn make_spawner(&self) -> TripSpawner { 149 TripSpawner::new() 150 } flush_spawner(&mut self, spawner: TripSpawner, map: &Map, timer: &mut Timer)151 pub fn flush_spawner(&mut self, spawner: TripSpawner, map: &Map, timer: &mut Timer) { 152 spawner.finalize(map, &mut self.trips, &mut self.scheduler, timer); 153 154 if let Some(ref mut m) = self.pandemic { 155 m.initialize(self.trips.get_all_people(), &mut self.scheduler); 156 } 157 158 self.dispatch_events(Vec::new(), map); 159 } 160 get_free_onstreet_spots(&self, l: LaneID) -> Vec<ParkingSpot>161 pub fn get_free_onstreet_spots(&self, l: LaneID) -> Vec<ParkingSpot> { 162 self.parking.get_free_onstreet_spots(l) 163 } 164 get_free_offstreet_spots(&self, b: BuildingID) -> Vec<ParkingSpot>165 pub fn get_free_offstreet_spots(&self, b: BuildingID) -> Vec<ParkingSpot> { 166 self.parking.get_free_offstreet_spots(b) 167 } 168 get_free_lot_spots(&self, pl: ParkingLotID) -> Vec<ParkingSpot>169 pub fn get_free_lot_spots(&self, pl: ParkingLotID) -> Vec<ParkingSpot> { 170 self.parking.get_free_lot_spots(pl) 171 } 172 173 // (Filled, available) get_all_parking_spots(&self) -> (Vec<ParkingSpot>, Vec<ParkingSpot>)174 pub fn get_all_parking_spots(&self) -> (Vec<ParkingSpot>, Vec<ParkingSpot>) { 175 self.parking.get_all_parking_spots() 176 } 177 178 // Also returns the start distance of the building. TODO Do that in the Path properly. walking_path_to_nearest_parking_spot( &self, map: &Map, b: BuildingID, ) -> Option<(Path, Distance)>179 pub fn walking_path_to_nearest_parking_spot( 180 &self, 181 map: &Map, 182 b: BuildingID, 183 ) -> Option<(Path, Distance)> { 184 let vehicle = Vehicle { 185 id: CarID(0, VehicleType::Car), 186 owner: None, 187 vehicle_type: VehicleType::Car, 188 length: MIN_CAR_LENGTH, 189 max_speed: None, 190 }; 191 let driving_lane = map.find_driving_lane_near_building(b); 192 193 // Anything on the current lane? TODO Should find the closest one to the sidewalk, but 194 // need a new method in ParkingSimState to make that easy. 195 // TODO Refactor the logic in router 196 let spot = if let Some((spot, _)) = self 197 .parking 198 .get_all_free_spots(Position::start(driving_lane), &vehicle, b, map) 199 .get(0) 200 { 201 spot.clone() 202 } else { 203 let (_, spot, _) = 204 self.parking 205 .path_to_free_parking_spot(driving_lane, &vehicle, b, map)?; 206 spot 207 }; 208 209 let start = SidewalkSpot::building(b, map).sidewalk_pos; 210 let end = SidewalkSpot::parking_spot(spot, map, &self.parking).sidewalk_pos; 211 let path = map.pathfind(PathRequest { 212 start, 213 end, 214 constraints: PathConstraints::Pedestrian, 215 })?; 216 Some((path, start.dist_along())) 217 } 218 219 // TODO Should these two be in TripSpawner? new_person( &mut self, p: PersonID, orig_id: Option<OrigPersonID>, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>, )220 pub(crate) fn new_person( 221 &mut self, 222 p: PersonID, 223 orig_id: Option<OrigPersonID>, 224 ped_speed: Speed, 225 vehicle_specs: Vec<VehicleSpec>, 226 ) { 227 self.trips.new_person(p, orig_id, ped_speed, vehicle_specs); 228 } random_person(&mut self, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>) -> &Person229 pub fn random_person(&mut self, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>) -> &Person { 230 self.trips.random_person(ped_speed, vehicle_specs) 231 } seed_parked_car(&mut self, vehicle: Vehicle, spot: ParkingSpot)232 pub(crate) fn seed_parked_car(&mut self, vehicle: Vehicle, spot: ParkingSpot) { 233 self.parking.reserve_spot(spot); 234 self.parking.add_parked_car(ParkedCar { vehicle, spot }); 235 } 236 seed_bus_route(&mut self, route: &BusRoute)237 pub(crate) fn seed_bus_route(&mut self, route: &BusRoute) { 238 for t in &route.spawn_times { 239 self.scheduler.push(*t, Command::StartBus(route.id, *t)); 240 } 241 } 242 start_bus(&mut self, route: &BusRoute, map: &Map)243 fn start_bus(&mut self, route: &BusRoute, map: &Map) { 244 // Spawn one bus for the first leg. 245 let (req, path) = self.transit.create_empty_route(route, map); 246 247 // For now, no desire for randomness. Caller can pass in list of specs if that ever 248 // changes. 249 let (vehicle_type, length) = match route.route_type { 250 PathConstraints::Bus => (VehicleType::Bus, BUS_LENGTH), 251 PathConstraints::Train => (VehicleType::Train, LIGHT_RAIL_LENGTH), 252 _ => unreachable!(), 253 }; 254 let vehicle = VehicleSpec { 255 vehicle_type, 256 length, 257 max_speed: None, 258 } 259 .make(CarID(self.trips.new_car_id(), vehicle_type), None); 260 let start_lane = map.get_l(path.current_step().as_lane()); 261 let start_dist = if map.get_i(start_lane.src_i).is_incoming_border() { 262 SPAWN_DIST 263 } else { 264 assert!(start_lane.length() > vehicle.length); 265 vehicle.length 266 }; 267 268 self.scheduler.push( 269 self.time, 270 Command::SpawnCar( 271 CreateCar { 272 start_dist, 273 router: Router::follow_bus_route( 274 vehicle.id, 275 path.clone(), 276 req.end.dist_along(), 277 ), 278 vehicle, 279 req, 280 maybe_parked_car: None, 281 trip_and_person: None, 282 maybe_route: Some(route.id), 283 }, 284 true, 285 ), 286 ); 287 } 288 set_name(&mut self, name: String)289 pub fn set_name(&mut self, name: String) { 290 self.run_name = name; 291 } 292 } 293 294 // Drawing 295 impl GetDrawAgents for Sim { time(&self) -> Time296 fn time(&self) -> Time { 297 self.time 298 } 299 step_count(&self) -> usize300 fn step_count(&self) -> usize { 301 self.step_count 302 } 303 get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCarInput>304 fn get_draw_car(&self, id: CarID, map: &Map) -> Option<DrawCarInput> { 305 self.parking.get_draw_car(id, map).or_else(|| { 306 self.driving 307 .get_single_draw_car(id, self.time, map, &self.transit) 308 }) 309 } 310 get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option<DrawPedestrianInput>311 fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option<DrawPedestrianInput> { 312 self.walking.get_draw_ped(id, self.time, map) 313 } 314 get_draw_cars(&self, on: Traversable, map: &Map) -> Vec<DrawCarInput>315 fn get_draw_cars(&self, on: Traversable, map: &Map) -> Vec<DrawCarInput> { 316 let mut results = Vec::new(); 317 if let Traversable::Lane(l) = on { 318 if map.get_l(l).is_parking() { 319 return self.parking.get_draw_cars(l, map); 320 } 321 results.extend(self.parking.get_draw_cars_in_lots(l, map)); 322 } 323 results.extend( 324 self.driving 325 .get_draw_cars_on(self.time, on, map, &self.transit), 326 ); 327 results 328 } 329 get_draw_peds( &self, on: Traversable, map: &Map, ) -> (Vec<DrawPedestrianInput>, Vec<DrawPedCrowdInput>)330 fn get_draw_peds( 331 &self, 332 on: Traversable, 333 map: &Map, 334 ) -> (Vec<DrawPedestrianInput>, Vec<DrawPedCrowdInput>) { 335 self.walking.get_draw_peds_on(self.time, on, map) 336 } 337 get_all_draw_cars(&self, map: &Map) -> Vec<DrawCarInput>338 fn get_all_draw_cars(&self, map: &Map) -> Vec<DrawCarInput> { 339 let mut result = self 340 .driving 341 .get_all_draw_cars(self.time, map, &self.transit); 342 result.extend(self.parking.get_all_draw_cars(map)); 343 result 344 } 345 get_all_draw_peds(&self, map: &Map) -> Vec<DrawPedestrianInput>346 fn get_all_draw_peds(&self, map: &Map) -> Vec<DrawPedestrianInput> { 347 self.walking.get_all_draw_peds(self.time, map) 348 } 349 get_unzoomed_agents(&self, map: &Map) -> Vec<UnzoomedAgent>350 fn get_unzoomed_agents(&self, map: &Map) -> Vec<UnzoomedAgent> { 351 let mut result = self.driving.get_unzoomed_agents(self.time, map); 352 result.extend(self.walking.get_unzoomed_agents(self.time, map)); 353 result 354 } 355 } 356 357 // Running 358 impl Sim { 359 // Advances time as minimally as possible, also limited by max_dt. Returns true if the callback 360 // said to halt the sim. minimal_step( &mut self, map: &Map, max_dt: Duration, maybe_cb: &mut Option<Box<dyn SimCallback>>, ) -> bool361 fn minimal_step( 362 &mut self, 363 map: &Map, 364 max_dt: Duration, 365 maybe_cb: &mut Option<Box<dyn SimCallback>>, 366 ) -> bool { 367 self.step_count += 1; 368 369 let max_time = if let Some(t) = self.scheduler.peek_next_time() { 370 if t > self.time + max_dt { 371 // Next event is after when we want to stop. 372 self.time += max_dt; 373 return false; 374 } 375 t 376 } else { 377 // No events left at all 378 self.time += max_dt; 379 return false; 380 }; 381 382 let mut halt = false; 383 while let Some(time) = self.scheduler.peek_next_time() { 384 if time > max_time { 385 return false; 386 } 387 if let Some(cmd) = self.scheduler.get_next() { 388 if self.do_step(map, time, cmd, maybe_cb) { 389 halt = true; 390 break; 391 } 392 } 393 } 394 395 halt 396 } 397 398 // If true, halt simulation because the callback said so. do_step( &mut self, map: &Map, time: Time, cmd: Command, maybe_cb: &mut Option<Box<dyn SimCallback>>, ) -> bool399 fn do_step( 400 &mut self, 401 map: &Map, 402 time: Time, 403 cmd: Command, 404 maybe_cb: &mut Option<Box<dyn SimCallback>>, 405 ) -> bool { 406 self.time = time; 407 let mut events = Vec::new(); 408 let mut halt = false; 409 410 let mut ctx = Ctx { 411 parking: &mut self.parking, 412 intersections: &mut self.intersections, 413 cap: &mut self.cap, 414 scheduler: &mut self.scheduler, 415 map, 416 }; 417 418 match cmd { 419 Command::StartTrip(id, trip_spec, maybe_req, maybe_path) => { 420 self.trips 421 .start_trip(self.time, id, trip_spec, maybe_req, maybe_path, &mut ctx); 422 } 423 Command::SpawnCar(create_car, retry_if_no_room) => { 424 if self.driving.start_car_on_lane( 425 self.time, 426 create_car.clone(), 427 map, 428 &self.intersections, 429 &self.parking, 430 &mut self.scheduler, 431 ) { 432 if let Some((trip, person)) = create_car.trip_and_person { 433 self.trips 434 .agent_starting_trip_leg(AgentID::Car(create_car.vehicle.id), trip); 435 events.push(Event::TripPhaseStarting( 436 trip, 437 person, 438 Some(create_car.req.clone()), 439 if create_car.vehicle.id.1 == VehicleType::Car { 440 TripPhaseType::Driving 441 } else { 442 TripPhaseType::Biking 443 }, 444 )); 445 } 446 if let Some(parked_car) = create_car.maybe_parked_car { 447 if let ParkingSpot::Offstreet(b, _) = parked_car.spot { 448 // Buses don't start in parking garages, so trip must exist 449 events.push(Event::PersonLeavesBuilding( 450 create_car.trip_and_person.unwrap().1, 451 b, 452 )); 453 } 454 self.parking.remove_parked_car(parked_car); 455 } 456 if let Some(route) = create_car.maybe_route { 457 self.transit.bus_created(create_car.vehicle.id, route); 458 } 459 self.analytics 460 .record_demand(create_car.router.get_path(), map); 461 } else if retry_if_no_room { 462 // TODO Record this in the trip log 463 self.scheduler.push( 464 self.time + BLIND_RETRY_TO_SPAWN, 465 Command::SpawnCar(create_car, retry_if_no_room), 466 ); 467 } else { 468 // Buses don't use Command::SpawnCar, so this must exist. 469 let (trip, person) = create_car.trip_and_person.unwrap(); 470 println!( 471 "No room to spawn car for {} by {}. Not retrying!", 472 trip, person 473 ); 474 // Have to redeclare for the borrow checker 475 let mut ctx = Ctx { 476 parking: &mut self.parking, 477 intersections: &mut self.intersections, 478 cap: &mut self.cap, 479 scheduler: &mut self.scheduler, 480 map, 481 }; 482 self.trips 483 .abort_trip(self.time, trip, Some(create_car.vehicle), &mut ctx); 484 } 485 } 486 Command::SpawnPed(create_ped) => { 487 // Do the order a bit backwards so we don't have to clone the 488 // CreatePedestrian. spawn_ped can't fail. 489 self.trips 490 .agent_starting_trip_leg(AgentID::Pedestrian(create_ped.id), create_ped.trip); 491 events.push(Event::TripPhaseStarting( 492 create_ped.trip, 493 create_ped.person, 494 Some(create_ped.req.clone()), 495 TripPhaseType::Walking, 496 )); 497 self.analytics.record_demand(&create_ped.path, map); 498 499 // Maybe there's actually no work to do! 500 match (&create_ped.start.connection, &create_ped.goal.connection) { 501 ( 502 SidewalkPOI::Building(b1), 503 SidewalkPOI::ParkingSpot(ParkingSpot::Offstreet(b2, idx)), 504 ) if b1 == b2 => { 505 self.trips.ped_reached_parking_spot( 506 self.time, 507 create_ped.id, 508 ParkingSpot::Offstreet(*b2, *idx), 509 Duration::ZERO, 510 &mut ctx, 511 ); 512 } 513 _ => { 514 if let SidewalkPOI::Building(b) = &create_ped.start.connection { 515 events.push(Event::PersonLeavesBuilding(create_ped.person, *b)); 516 } 517 518 self.walking 519 .spawn_ped(self.time, create_ped, map, &mut self.scheduler); 520 } 521 } 522 } 523 Command::UpdateCar(car) => { 524 self.driving.update_car( 525 car, 526 self.time, 527 &mut ctx, 528 &mut self.trips, 529 &mut self.transit, 530 &mut self.walking, 531 ); 532 } 533 Command::UpdateLaggyHead(car) => { 534 self.driving.update_laggy_head( 535 car, 536 self.time, 537 map, 538 &mut self.intersections, 539 &mut self.scheduler, 540 ); 541 } 542 Command::UpdatePed(ped) => { 543 self.walking.update_ped( 544 ped, 545 self.time, 546 &mut ctx, 547 &mut self.trips, 548 &mut self.transit, 549 ); 550 } 551 Command::UpdateIntersection(i) => { 552 self.intersections 553 .update_intersection(self.time, i, map, &mut self.scheduler); 554 } 555 Command::Callback(frequency) => { 556 self.scheduler 557 .push(self.time + frequency, Command::Callback(frequency)); 558 if maybe_cb.as_mut().unwrap().run(self, map) { 559 halt = true; 560 } 561 } 562 Command::Pandemic(cmd) => { 563 self.pandemic 564 .as_mut() 565 .unwrap() 566 .handle_cmd(self.time, cmd, &mut self.scheduler); 567 } 568 Command::FinishRemoteTrip(trip) => { 569 self.trips.remote_trip_finished(self.time, trip, &mut ctx); 570 } 571 Command::StartBus(r, _) => { 572 self.start_bus(map.get_br(r), map); 573 } 574 } 575 576 // Record events at precisely the time they occur. 577 self.dispatch_events(events, map); 578 579 halt 580 } 581 dispatch_events(&mut self, mut events: Vec<Event>, map: &Map)582 fn dispatch_events(&mut self, mut events: Vec<Event>, map: &Map) { 583 events.extend(self.trips.collect_events()); 584 events.extend(self.transit.collect_events()); 585 events.extend(self.driving.collect_events()); 586 events.extend(self.walking.collect_events()); 587 events.extend(self.intersections.collect_events()); 588 events.extend(self.parking.collect_events()); 589 for ev in events { 590 if let Some(ref mut m) = self.pandemic { 591 m.handle_event(self.time, &ev, &mut self.scheduler); 592 } 593 594 self.analytics.event(ev, self.time, map); 595 } 596 } 597 timed_step( &mut self, map: &Map, dt: Duration, maybe_cb: &mut Option<Box<dyn SimCallback>>, timer: &mut Timer, )598 pub fn timed_step( 599 &mut self, 600 map: &Map, 601 dt: Duration, 602 maybe_cb: &mut Option<Box<dyn SimCallback>>, 603 timer: &mut Timer, 604 ) { 605 let end_time = self.time + dt; 606 let start = Instant::now(); 607 let mut last_update = Instant::now(); 608 609 timer.start(format!("Advance sim to {}", end_time)); 610 while self.time < end_time { 611 if self.minimal_step(map, end_time - self.time, maybe_cb) { 612 break; 613 } 614 if !self.analytics.alerts.is_empty() { 615 match self.alerts { 616 AlertHandler::Print => { 617 for (t, loc, msg) in self.analytics.alerts.drain(..) { 618 println!("Alert at {} ({:?}): {}", t, loc, msg); 619 } 620 } 621 AlertHandler::Block => { 622 for (t, loc, msg) in &self.analytics.alerts { 623 println!("Alert at {} ({:?}): {}", t, loc, msg); 624 } 625 break; 626 } 627 AlertHandler::Silence => { 628 self.analytics.alerts.clear(); 629 } 630 } 631 } 632 if Duration::realtime_elapsed(last_update) >= Duration::seconds(1.0) { 633 // TODO Not timer? 634 println!( 635 "- After {}, the sim is at {}. {} live agents", 636 Duration::realtime_elapsed(start), 637 self.time, 638 prettyprint_usize(self.trips.num_active_agents()), 639 ); 640 last_update = Instant::now(); 641 } 642 } 643 timer.stop(format!("Advance sim to {}", end_time)); 644 } tiny_step(&mut self, map: &Map, maybe_cb: &mut Option<Box<dyn SimCallback>>)645 pub fn tiny_step(&mut self, map: &Map, maybe_cb: &mut Option<Box<dyn SimCallback>>) { 646 self.timed_step( 647 map, 648 Duration::seconds(0.1), 649 maybe_cb, 650 &mut Timer::throwaway(), 651 ); 652 } 653 time_limited_step( &mut self, map: &Map, dt: Duration, real_time_limit: Duration, maybe_cb: &mut Option<Box<dyn SimCallback>>, )654 pub fn time_limited_step( 655 &mut self, 656 map: &Map, 657 dt: Duration, 658 real_time_limit: Duration, 659 maybe_cb: &mut Option<Box<dyn SimCallback>>, 660 ) { 661 let started_at = Instant::now(); 662 let end_time = self.time + dt; 663 664 while self.time < end_time && Duration::realtime_elapsed(started_at) < real_time_limit { 665 if self.minimal_step(map, end_time - self.time, maybe_cb) { 666 break; 667 } 668 if !self.analytics.alerts.is_empty() { 669 match self.alerts { 670 AlertHandler::Print => { 671 for (t, loc, msg) in self.analytics.alerts.drain(..) { 672 println!("Alert at {} ({:?}): {}", t, loc, msg); 673 } 674 } 675 AlertHandler::Block => { 676 for (t, loc, msg) in &self.analytics.alerts { 677 println!("Alert at {} ({:?}): {}", t, loc, msg); 678 } 679 break; 680 } 681 AlertHandler::Silence => { 682 self.analytics.alerts.clear(); 683 } 684 } 685 } 686 } 687 } 688 dump_before_abort(&self)689 pub fn dump_before_abort(&self) { 690 println!("At {}", self.time); 691 if let Some(path) = self.find_previous_savestate(self.time) { 692 println!("Debug from {}", path); 693 } 694 } 695 } 696 697 // Helpers to run the sim 698 // TODO Old and gunky 699 impl Sim { run_until_done<F: Fn(&mut Sim, &Map)>( &mut self, map: &Map, callback: F, time_limit: Option<Duration>, )700 pub fn run_until_done<F: Fn(&mut Sim, &Map)>( 701 &mut self, 702 map: &Map, 703 callback: F, 704 // Interpreted as a relative time 705 time_limit: Option<Duration>, 706 ) { 707 let mut last_print = Instant::now(); 708 let mut last_sim_time = self.time(); 709 710 loop { 711 // TODO Regular printing doesn't happen if we use a time_limit :\ 712 let dt = time_limit.unwrap_or_else(|| Duration::seconds(30.0)); 713 714 match panic::catch_unwind(panic::AssertUnwindSafe(|| { 715 self.timed_step(map, dt, &mut None, &mut Timer::throwaway()); 716 })) { 717 Ok(()) => {} 718 Err(err) => { 719 println!( 720 "*************************************************************************\ 721 *******" 722 ); 723 println!("Sim broke:"); 724 self.dump_before_abort(); 725 panic::resume_unwind(err); 726 } 727 } 728 729 let dt_real = Duration::realtime_elapsed(last_print); 730 if dt_real >= Duration::seconds(1.0) { 731 let (finished, unfinished) = self.num_trips(); 732 println!( 733 "{}: {} trips finished, {} unfinished, speed = {:.2}x, {}", 734 self.time(), 735 prettyprint_usize(finished), 736 prettyprint_usize(unfinished), 737 (self.time() - last_sim_time) / dt_real, 738 self.scheduler.describe_stats() 739 ); 740 last_print = Instant::now(); 741 last_sim_time = self.time(); 742 } 743 callback(self, map); 744 if self.is_done() { 745 println!( 746 "{}: speed = {:.2}x, {}", 747 self.time(), 748 (self.time() - last_sim_time) / dt_real, 749 self.scheduler.describe_stats() 750 ); 751 break; 752 } 753 754 if let Some(lim) = time_limit { 755 panic!("Time limit {} hit", lim); 756 } 757 } 758 } 759 } 760 761 // Savestating 762 impl Sim { save_dir(&self) -> String763 pub fn save_dir(&self) -> String { 764 abstutil::path_all_saves(&self.map_name, &self.edits_name, &self.run_name) 765 } 766 save_path(&self, base_time: Time) -> String767 fn save_path(&self, base_time: Time) -> String { 768 // If we wanted to be even more reproducible, we'd encode RNG seed, version of code, etc, 769 // but that's overkill right now. 770 abstutil::path_save( 771 &self.map_name, 772 &self.edits_name, 773 &self.run_name, 774 base_time.as_filename(), 775 ) 776 } 777 save(&mut self) -> String778 pub fn save(&mut self) -> String { 779 let restore = self.scheduler.before_savestate(); 780 781 if true { 782 println!("sim savestate breakdown:"); 783 println!( 784 "- driving: {} bytes", 785 prettyprint_usize(serialized_size_bytes(&self.driving)) 786 ); 787 println!( 788 "- parking: {} bytes", 789 prettyprint_usize(serialized_size_bytes(&self.parking)) 790 ); 791 println!( 792 "- walking: {} bytes", 793 prettyprint_usize(serialized_size_bytes(&self.walking)) 794 ); 795 println!( 796 "- intersections: {} bytes", 797 prettyprint_usize(serialized_size_bytes(&self.intersections)) 798 ); 799 println!( 800 "- transit: {} bytes", 801 prettyprint_usize(serialized_size_bytes(&self.transit)) 802 ); 803 println!( 804 "- cap: {} bytes", 805 prettyprint_usize(serialized_size_bytes(&self.cap)) 806 ); 807 println!( 808 "- trips: {} bytes", 809 prettyprint_usize(serialized_size_bytes(&self.trips)) 810 ); 811 println!( 812 "- scheduler: {} bytes", 813 prettyprint_usize(serialized_size_bytes(&self.scheduler)) 814 ); 815 } 816 817 let path = self.save_path(self.time); 818 abstutil::write_binary(path.clone(), self); 819 820 self.scheduler.after_savestate(restore); 821 822 path 823 } 824 find_previous_savestate(&self, base_time: Time) -> Option<String>825 pub fn find_previous_savestate(&self, base_time: Time) -> Option<String> { 826 abstutil::find_prev_file(self.save_path(base_time)) 827 } 828 find_next_savestate(&self, base_time: Time) -> Option<String>829 pub fn find_next_savestate(&self, base_time: Time) -> Option<String> { 830 abstutil::find_next_file(self.save_path(base_time)) 831 } 832 load_savestate( path: String, map: &Map, timer: &mut Timer, ) -> Result<Sim, std::io::Error>833 pub fn load_savestate( 834 path: String, 835 map: &Map, 836 timer: &mut Timer, 837 ) -> Result<Sim, std::io::Error> { 838 let mut sim: Sim = abstutil::maybe_read_binary(path, timer)?; 839 sim.restore_paths(map, timer); 840 Ok(sim) 841 } 842 restore_paths(&mut self, map: &Map, timer: &mut Timer)843 pub fn restore_paths(&mut self, map: &Map, timer: &mut Timer) { 844 let paths = timer.parallelize( 845 "calculate paths", 846 Parallelism::Fastest, 847 self.scheduler.get_requests_for_savestate(), 848 |req| map.pathfind(req).unwrap(), 849 ); 850 self.scheduler.after_savestate(paths); 851 } 852 handle_live_edited_traffic_signals(&mut self, map: &Map)853 pub fn handle_live_edited_traffic_signals(&mut self, map: &Map) { 854 self.intersections.handle_live_edited_traffic_signals(map) 855 } 856 } 857 858 // Queries of all sorts 859 // TODO Many of these just delegate to an inner piece. This is unorganized and hard to maintain. 860 impl Sim { time(&self) -> Time861 pub fn time(&self) -> Time { 862 self.time 863 } 864 is_done(&self) -> bool865 pub fn is_done(&self) -> bool { 866 self.trips.is_done() 867 } 868 is_empty(&self) -> bool869 pub fn is_empty(&self) -> bool { 870 self.time == Time::START_OF_DAY && self.is_done() 871 } 872 873 // (number of finished trips, number of unfinished trips) num_trips(&self) -> (usize, usize)874 pub fn num_trips(&self) -> (usize, usize) { 875 self.trips.num_trips() 876 } num_agents(&self) -> Counter<AgentType>877 pub fn num_agents(&self) -> Counter<AgentType> { 878 self.trips.num_agents(&self.transit) 879 } 880 // (total number of people, just in buildings, just off map) num_ppl(&self) -> (usize, usize, usize)881 pub fn num_ppl(&self) -> (usize, usize, usize) { 882 self.trips.num_ppl() 883 } 884 debug_ped(&self, id: PedestrianID)885 pub fn debug_ped(&self, id: PedestrianID) { 886 self.walking.debug_ped(id); 887 self.trips.debug_trip(AgentID::Pedestrian(id)); 888 } 889 debug_car(&self, id: CarID)890 pub fn debug_car(&self, id: CarID) { 891 self.driving.debug_car(id); 892 self.trips.debug_trip(AgentID::Car(id)); 893 } 894 debug_intersection(&self, id: IntersectionID, map: &Map)895 pub fn debug_intersection(&self, id: IntersectionID, map: &Map) { 896 self.intersections.debug(id, map); 897 } 898 debug_lane(&self, id: LaneID)899 pub fn debug_lane(&self, id: LaneID) { 900 self.driving.debug_lane(id); 901 } 902 903 // Only call for active agents, will panic otherwise agent_properties(&self, id: AgentID) -> AgentProperties904 pub fn agent_properties(&self, id: AgentID) -> AgentProperties { 905 match id { 906 AgentID::Pedestrian(id) => self.walking.agent_properties(id, self.time), 907 AgentID::Car(id) => self.driving.agent_properties(id, self.time), 908 // TODO Harder to measure some of this stuff 909 AgentID::BusPassenger(_, _) => AgentProperties { 910 total_time: Duration::ZERO, 911 waiting_here: Duration::ZERO, 912 total_waiting: Duration::ZERO, 913 dist_crossed: Distance::ZERO, 914 total_dist: Distance::meters(0.1), 915 lanes_crossed: 0, 916 total_lanes: 0, 917 }, 918 } 919 } 920 num_transit_passengers(&self, car: CarID) -> usize921 pub fn num_transit_passengers(&self, car: CarID) -> usize { 922 self.transit.get_passengers(car).len() 923 } 924 bus_route_id(&self, maybe_bus: CarID) -> Option<BusRouteID>925 pub fn bus_route_id(&self, maybe_bus: CarID) -> Option<BusRouteID> { 926 if maybe_bus.1 == VehicleType::Bus || maybe_bus.1 == VehicleType::Train { 927 Some(self.transit.bus_route(maybe_bus)) 928 } else { 929 None 930 } 931 } 932 active_agents(&self) -> Vec<AgentID>933 pub fn active_agents(&self) -> Vec<AgentID> { 934 self.trips.active_agents() 935 } 936 agent_to_trip(&self, id: AgentID) -> Option<TripID>937 pub fn agent_to_trip(&self, id: AgentID) -> Option<TripID> { 938 self.trips.agent_to_trip(id) 939 } 940 trip_to_agent(&self, id: TripID) -> TripResult<AgentID>941 pub fn trip_to_agent(&self, id: TripID) -> TripResult<AgentID> { 942 self.trips.trip_to_agent(id) 943 } 944 trip_info(&self, id: TripID) -> TripInfo945 pub fn trip_info(&self, id: TripID) -> TripInfo { 946 self.trips.trip_info(id) 947 } all_trip_info(&self) -> Vec<(TripID, TripInfo)>948 pub fn all_trip_info(&self) -> Vec<(TripID, TripInfo)> { 949 self.trips.all_trip_info() 950 } 951 // If trip is finished, returns (total time, total waiting time) finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)>952 pub fn finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)> { 953 self.trips.finished_trip_time(id) 954 } 955 trip_to_person(&self, id: TripID) -> PersonID956 pub fn trip_to_person(&self, id: TripID) -> PersonID { 957 self.trips.trip_to_person(id) 958 } 959 // TODO This returns None for parked cars owned by people! That's confusing. Dedupe with 960 // get_owner_of_car. agent_to_person(&self, id: AgentID) -> Option<PersonID>961 pub fn agent_to_person(&self, id: AgentID) -> Option<PersonID> { 962 self.agent_to_trip(id).map(|t| self.trip_to_person(t)) 963 } get_owner_of_car(&self, id: CarID) -> Option<PersonID>964 pub fn get_owner_of_car(&self, id: CarID) -> Option<PersonID> { 965 self.driving 966 .get_owner_of_car(id) 967 .or_else(|| self.parking.get_owner_of_car(id)) 968 } lookup_parked_car(&self, id: CarID) -> Option<&ParkedCar>969 pub fn lookup_parked_car(&self, id: CarID) -> Option<&ParkedCar> { 970 self.parking.lookup_parked_car(id) 971 } 972 lookup_person(&self, id: PersonID) -> Option<&Person>973 pub fn lookup_person(&self, id: PersonID) -> Option<&Person> { 974 self.trips.get_person(id) 975 } get_person(&self, id: PersonID) -> &Person976 pub fn get_person(&self, id: PersonID) -> &Person { 977 self.trips.get_person(id).unwrap() 978 } find_person_by_orig_id(&self, id: OrigPersonID) -> Option<PersonID>979 pub fn find_person_by_orig_id(&self, id: OrigPersonID) -> Option<PersonID> { 980 for p in self.get_all_people() { 981 if p.orig_id == Some(id) { 982 return Some(p.id); 983 } 984 } 985 None 986 } get_all_people(&self) -> &Vec<Person>987 pub fn get_all_people(&self) -> &Vec<Person> { 988 self.trips.get_all_people() 989 } 990 lookup_car_id(&self, idx: usize) -> Option<CarID>991 pub fn lookup_car_id(&self, idx: usize) -> Option<CarID> { 992 for vt in &[ 993 VehicleType::Car, 994 VehicleType::Bike, 995 VehicleType::Bus, 996 VehicleType::Train, 997 ] { 998 let id = CarID(idx, *vt); 999 if self.driving.does_car_exist(id) { 1000 return Some(id); 1001 } 1002 } 1003 1004 let id = CarID(idx, VehicleType::Car); 1005 // Only cars can be parked. 1006 if self.parking.lookup_parked_car(id).is_some() { 1007 return Some(id); 1008 } 1009 1010 None 1011 } 1012 get_path(&self, id: AgentID) -> Option<&Path>1013 pub fn get_path(&self, id: AgentID) -> Option<&Path> { 1014 match id { 1015 AgentID::Car(car) => self.driving.get_path(car), 1016 AgentID::Pedestrian(ped) => self.walking.get_path(ped), 1017 AgentID::BusPassenger(_, _) => None, 1018 } 1019 } get_all_driving_paths(&self) -> Vec<&Path>1020 pub fn get_all_driving_paths(&self) -> Vec<&Path> { 1021 self.driving.get_all_driving_paths() 1022 } 1023 trace_route( &self, id: AgentID, map: &Map, dist_ahead: Option<Distance>, ) -> Option<PolyLine>1024 pub fn trace_route( 1025 &self, 1026 id: AgentID, 1027 map: &Map, 1028 dist_ahead: Option<Distance>, 1029 ) -> Option<PolyLine> { 1030 match id { 1031 AgentID::Car(car) => self.driving.trace_route(self.time, car, map, dist_ahead), 1032 AgentID::Pedestrian(ped) => self.walking.trace_route(self.time, ped, map, dist_ahead), 1033 AgentID::BusPassenger(_, _) => None, 1034 } 1035 } 1036 get_canonical_pt_per_trip(&self, trip: TripID, map: &Map) -> TripResult<Pt2D>1037 pub fn get_canonical_pt_per_trip(&self, trip: TripID, map: &Map) -> TripResult<Pt2D> { 1038 let agent = match self.trips.trip_to_agent(trip) { 1039 TripResult::Ok(a) => a, 1040 x => { 1041 return x.propagate_error(); 1042 } 1043 }; 1044 if let Some(pt) = self.canonical_pt_for_agent(agent, map) { 1045 return TripResult::Ok(pt); 1046 } 1047 TripResult::ModeChange 1048 } get_canonical_pt_per_person(&self, p: PersonID, map: &Map) -> Option<Pt2D>1049 pub fn get_canonical_pt_per_person(&self, p: PersonID, map: &Map) -> Option<Pt2D> { 1050 match self.trips.get_person(p)?.state { 1051 PersonState::Inside(b) => Some(map.get_b(b).polygon.center()), 1052 PersonState::Trip(t) => self.get_canonical_pt_per_trip(t, map).ok(), 1053 PersonState::OffMap => None, 1054 } 1055 } 1056 canonical_pt_for_agent(&self, id: AgentID, map: &Map) -> Option<Pt2D>1057 pub fn canonical_pt_for_agent(&self, id: AgentID, map: &Map) -> Option<Pt2D> { 1058 match id { 1059 AgentID::Car(id) => self 1060 .parking 1061 .canonical_pt(id, map) 1062 .or_else(|| Some(self.get_draw_car(id, map)?.body.last_pt())), 1063 AgentID::Pedestrian(id) => Some(self.get_draw_ped(id, map)?.pos), 1064 AgentID::BusPassenger(_, bus) => Some(self.get_draw_car(bus, map)?.body.last_pt()), 1065 } 1066 } 1067 get_accepted_agents(&self, id: IntersectionID) -> HashSet<AgentID>1068 pub fn get_accepted_agents(&self, id: IntersectionID) -> HashSet<AgentID> { 1069 self.intersections.get_accepted_agents(id) 1070 } get_blocked_by(&self, a: AgentID) -> HashSet<AgentID>1071 pub fn get_blocked_by(&self, a: AgentID) -> HashSet<AgentID> { 1072 self.intersections.get_blocked_by(a) 1073 } 1074 1075 // (bus, stop index it's coming from, percent to next stop, location) status_of_buses( &self, route: BusRouteID, map: &Map, ) -> Vec<(CarID, Option<usize>, f64, Pt2D)>1076 pub fn status_of_buses( 1077 &self, 1078 route: BusRouteID, 1079 map: &Map, 1080 ) -> Vec<(CarID, Option<usize>, f64, Pt2D)> { 1081 let mut results = Vec::new(); 1082 for (bus, stop_idx) in self.transit.buses_for_route(route) { 1083 results.push(( 1084 bus, 1085 stop_idx, 1086 self.driving.percent_along_route(bus), 1087 self.canonical_pt_for_agent(AgentID::Car(bus), map).unwrap(), 1088 )); 1089 } 1090 results 1091 } 1092 get_analytics(&self) -> &Analytics1093 pub fn get_analytics(&self) -> &Analytics { 1094 &self.analytics 1095 } 1096 find_blockage_front(&self, car: CarID, map: &Map) -> String1097 pub fn find_blockage_front(&self, car: CarID, map: &Map) -> String { 1098 self.driving 1099 .find_blockage_front(car, map, &self.intersections) 1100 } 1101 1102 // For intersections with an agent waiting beyond some threshold, return when they started 1103 // waiting. Sorted by earliest waiting (likely the root cause of gridlock). delayed_intersections(&self, threshold: Duration) -> Vec<(IntersectionID, Time)>1104 pub fn delayed_intersections(&self, threshold: Duration) -> Vec<(IntersectionID, Time)> { 1105 self.intersections 1106 .delayed_intersections(self.time, threshold) 1107 } 1108 bldg_to_people(&self, b: BuildingID) -> Vec<PersonID>1109 pub fn bldg_to_people(&self, b: BuildingID) -> Vec<PersonID> { 1110 self.trips.bldg_to_people(b) 1111 } 1112 worst_delay( &self, map: &Map, ) -> ( BTreeMap<RoadID, Duration>, BTreeMap<IntersectionID, Duration>, )1113 pub fn worst_delay( 1114 &self, 1115 map: &Map, 1116 ) -> ( 1117 BTreeMap<RoadID, Duration>, 1118 BTreeMap<IntersectionID, Duration>, 1119 ) { 1120 self.intersections.worst_delay(self.time, map) 1121 } 1122 get_pandemic_model(&self) -> Option<&PandemicModel>1123 pub fn get_pandemic_model(&self) -> Option<&PandemicModel> { 1124 self.pandemic.as_ref() 1125 } 1126 get_end_of_day(&self) -> Time1127 pub fn get_end_of_day(&self) -> Time { 1128 // Always count at least 24 hours 1129 self.scheduler 1130 .get_last_time() 1131 .max(Time::START_OF_DAY + Duration::hours(24)) 1132 } 1133 current_stage_and_remaining_time(&self, i: IntersectionID) -> (usize, Duration)1134 pub fn current_stage_and_remaining_time(&self, i: IntersectionID) -> (usize, Duration) { 1135 self.intersections 1136 .current_stage_and_remaining_time(self.time, i) 1137 } 1138 1139 // TODO This is an awkward copy of raw_throughput 1140 // TODO And it does NOT count buses/trains spawning all_arrivals_at_border( &self, i: IntersectionID, ) -> Vec<(AgentType, Vec<(Time, usize)>)>1141 pub fn all_arrivals_at_border( 1142 &self, 1143 i: IntersectionID, 1144 ) -> Vec<(AgentType, Vec<(Time, usize)>)> { 1145 let window_size = Duration::hours(1); 1146 let mut pts_per_type: BTreeMap<AgentType, Vec<(Time, usize)>> = BTreeMap::new(); 1147 let mut windows_per_type: BTreeMap<AgentType, Window> = BTreeMap::new(); 1148 for agent_type in AgentType::all() { 1149 pts_per_type.insert(agent_type, vec![(Time::START_OF_DAY, 0)]); 1150 windows_per_type.insert(agent_type, Window::new(window_size)); 1151 } 1152 1153 for (t, agent_type) in self.trips.all_arrivals_at_border(i) { 1154 let count = windows_per_type.get_mut(&agent_type).unwrap().add(t); 1155 pts_per_type.get_mut(&agent_type).unwrap().push((t, count)); 1156 } 1157 1158 for (agent_type, pts) in pts_per_type.iter_mut() { 1159 let mut window = windows_per_type.remove(agent_type).unwrap(); 1160 1161 // Add a drop-off after window_size (+ a little epsilon!) 1162 let end = self.get_end_of_day(); 1163 let t = (pts.last().unwrap().0 + window_size + Duration::seconds(0.1)).min(end); 1164 if pts.last().unwrap().0 != t { 1165 pts.push((t, window.count(t))); 1166 } 1167 1168 if pts.last().unwrap().0 != end { 1169 pts.push((end, window.count(end))); 1170 } 1171 } 1172 1173 pts_per_type.into_iter().collect() 1174 } 1175 1176 // (number of vehicles in the lane, penalty if a bike or other slow vehicle is present) target_lane_penalty(&self, lane: &Lane) -> (usize, usize)1177 pub fn target_lane_penalty(&self, lane: &Lane) -> (usize, usize) { 1178 if lane.is_walkable() { 1179 (0, 0) 1180 } else { 1181 self.driving.target_lane_penalty(lane.id) 1182 } 1183 } 1184 get_people_waiting_at_stop( &self, at: BusStopID, ) -> &Vec<(PedestrianID, BusRouteID, Option<BusStopID>, Time)>1185 pub fn get_people_waiting_at_stop( 1186 &self, 1187 at: BusStopID, 1188 ) -> &Vec<(PedestrianID, BusRouteID, Option<BusStopID>, Time)> { 1189 self.transit.get_people_waiting_at_stop(at) 1190 } 1191 generate_scenario(&self, map: &Map, name: String) -> Scenario1192 pub fn generate_scenario(&self, map: &Map, name: String) -> Scenario { 1193 self.trips.generate_scenario(map, name) 1194 } 1195 get_cap_counter(&self, l: LaneID) -> usize1196 pub fn get_cap_counter(&self, l: LaneID) -> usize { 1197 self.cap.get_cap_counter(l) 1198 } 1199 } 1200 1201 // Invasive debugging 1202 impl Sim { kill_stuck_car(&mut self, id: CarID, map: &Map)1203 pub fn kill_stuck_car(&mut self, id: CarID, map: &Map) { 1204 if let Some(trip) = self.agent_to_trip(AgentID::Car(id)) { 1205 let vehicle = self.driving.kill_stuck_car( 1206 id, 1207 self.time, 1208 map, 1209 &mut self.scheduler, 1210 &mut self.intersections, 1211 ); 1212 let mut ctx = Ctx { 1213 parking: &mut self.parking, 1214 intersections: &mut self.intersections, 1215 cap: &mut self.cap, 1216 scheduler: &mut self.scheduler, 1217 map, 1218 }; 1219 self.trips 1220 .abort_trip(self.time, trip, Some(vehicle), &mut ctx); 1221 println!("Forcibly killed {}", id); 1222 } else { 1223 println!("{} has no trip?!", id); 1224 } 1225 } 1226 clear_alerts(&mut self) -> Vec<(Time, AlertLocation, String)>1227 pub fn clear_alerts(&mut self) -> Vec<(Time, AlertLocation, String)> { 1228 std::mem::replace(&mut self.analytics.alerts, Vec::new()) 1229 } 1230 } 1231 1232 // Callbacks 1233 pub trait SimCallback: downcast_rs::Downcast { 1234 // Run at some scheduled time. If this returns true, halt simulation. run(&mut self, sim: &Sim, map: &Map) -> bool1235 fn run(&mut self, sim: &Sim, map: &Map) -> bool; 1236 } 1237 downcast_rs::impl_downcast!(SimCallback); 1238 1239 impl Sim { 1240 // Only one at a time supported. set_periodic_callback(&mut self, frequency: Duration)1241 pub fn set_periodic_callback(&mut self, frequency: Duration) { 1242 // TODO Round up time nicely? 1243 self.scheduler 1244 .push(self.time + frequency, Command::Callback(frequency)); 1245 } unset_periodic_callback(&mut self)1246 pub fn unset_periodic_callback(&mut self) { 1247 // Frequency doesn't matter 1248 self.scheduler 1249 .cancel(Command::Callback(Duration::seconds(1.0))); 1250 } 1251 } 1252 1253 pub struct AgentProperties { 1254 // TODO Of this leg of the trip only! 1255 pub total_time: Duration, 1256 pub waiting_here: Duration, 1257 pub total_waiting: Duration, 1258 1259 // TODO More continuous on a single lane 1260 pub dist_crossed: Distance, 1261 pub total_dist: Distance, 1262 1263 pub lanes_crossed: usize, 1264 pub total_lanes: usize, 1265 } 1266