sim/
prebake.rs

1use serde::Serialize;
2
3use crate::{AlertHandler, Sim, SimFlags, SimOptions};
4use abstutil::{prettyprint_usize, Timer};
5use geom::{Duration, Time};
6use map_model::Map;
7use synthpop::Scenario;
8
9/// Simulate a curated list of scenarios to completion, and save the analytics as "prebaked
10/// results," to later compare simulation metrics against the baseline without map edits.
11pub fn prebake(map: &Map, scenario: Scenario, timer: &mut Timer) -> PrebakeSummary {
12    timer.start(format!(
13        "prebake for {} / {}",
14        scenario.map_name.describe(),
15        scenario.scenario_name
16    ));
17
18    let mut opts = SimOptions::new("prebaked");
19    opts.alerts = AlertHandler::Silence;
20    let mut sim = Sim::new(map, opts);
21    // Bit of an abuse of this, but just need to fix the rng seed.
22    let mut rng = SimFlags::for_test("prebaked").make_rng();
23    sim.instantiate(&scenario, map, &mut rng, timer);
24
25    // Run until a few hours after the end of the day. Some trips start close to midnight, and we
26    // want prebaked data for them too.
27    sim.timed_step(
28        map,
29        sim.get_end_of_day() - Time::START_OF_DAY + Duration::hours(3),
30        &mut None,
31        timer,
32    );
33    abstio::write_binary(
34        abstio::path_prebaked_results(&scenario.map_name, &scenario.scenario_name),
35        sim.get_analytics(),
36    );
37    // TODO Remove the num_agents check once transit isn't as broken. In sao_miguel_paulista,
38    // people wait for a bus that stops running at midnight.
39    if !sim.is_done() && sim.num_agents().sum() > 200 {
40        panic!(
41            "It's {} and there are still {} agents left in {}. Gridlock likely...",
42            sim.time(),
43            prettyprint_usize(sim.num_agents().sum()),
44            scenario.map_name.describe()
45        );
46    }
47    timer.stop(format!(
48        "prebake for {} / {}",
49        scenario.map_name.describe(),
50        scenario.scenario_name
51    ));
52
53    PrebakeSummary::new(&sim, &scenario)
54}
55
56#[derive(Debug, Serialize)]
57pub struct PrebakeSummary {
58    pub map: String,
59    pub scenario: String,
60    pub finished_trips: usize,
61    pub cancelled_trips: usize,
62    pub total_trip_duration_seconds: f64,
63}
64
65impl PrebakeSummary {
66    pub fn new(sim: &Sim, scenario: &Scenario) -> Self {
67        let mut finished_trips = 0;
68        let mut cancelled_trips = 0;
69        // Use f64 seconds, since a serialized Duration has a low cap.
70        let mut total_trip_duration_seconds = 0.0;
71        for (_, _, _, maybe_duration) in &sim.get_analytics().finished_trips {
72            if let Some(dt) = maybe_duration {
73                finished_trips += 1;
74                total_trip_duration_seconds += dt.inner_seconds();
75            } else {
76                cancelled_trips += 1;
77            }
78        }
79        Self {
80            map: scenario.map_name.describe(),
81            scenario: scenario.scenario_name.clone(),
82            finished_trips,
83            cancelled_trips,
84            total_trip_duration_seconds,
85        }
86    }
87}