diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index 88bf36073f..2fbd39295c 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -374,9 +374,9 @@ data/system/maps/montlake.bin,79c11be1af5833a04c6cbb4746e04401,https://www.dropb data/system/maps/mt_baker.bin,312bff6b9609305be22cce8c02190315,https://www.dropbox.com/s/cetje663p04cbgp/mt_baker.bin.zip?dl=0 data/system/maps/udistrict.bin,870d0e3b89a56a294a5ad6e559fe22b8,https://www.dropbox.com/s/zqt2je8fadssz5j/udistrict.bin.zip?dl=0 data/system/maps/west_seattle.bin,804ff03d1a8b2975a26340d4cf9dbc52,https://www.dropbox.com/s/5pp1ik9l40yj3wh/west_seattle.bin.zip?dl=0 -data/system/prebaked_results/lakeslice/weekday.bin,3b646ecf92e16df3c33bf7dbf30132dc,https://www.dropbox.com/s/1c1sohvy50263wg/weekday.bin.zip?dl=0 -data/system/prebaked_results/montlake/car vs bike contention.bin,8c1c883a5dcd6daa042740033c0c18c4,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0 -data/system/prebaked_results/montlake/weekday.bin,ae43e474b1ab111615e2efde90135491,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0 +data/system/prebaked_results/lakeslice/weekday.bin,1bd9f0c4a5fef02a18ba7d4b35b4c16e,https://www.dropbox.com/s/q1twjx4xdfijm98/weekday.bin.zip?dl=0 +data/system/prebaked_results/montlake/car vs bike contention.bin,cf4e1d0352f19690e82c766c8c994c9f,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0 +data/system/prebaked_results/montlake/weekday.bin,9f331f13a18c83efb21c853ae2db3e7a,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0 data/system/scenarios/ballard/weekday.bin,60d3eb1cdb8672e2d29cf3acf23ccabe,https://www.dropbox.com/s/67hys1v7m7oe979/weekday.bin.zip?dl=0 data/system/scenarios/downtown/weekday.bin,c3d252010b69e973f20b2cd8022e0fe5,https://www.dropbox.com/s/pstvu4p7xj3gaoi/weekday.bin.zip?dl=0 data/system/scenarios/huge_seattle/weekday.bin,31bfc23f39bb54bef939119f6cfbd2e2,https://www.dropbox.com/s/u3pmsshwnf13g83/weekday.bin.zip?dl=0 diff --git a/game/src/info/intersection.rs b/game/src/info/intersection.rs index ab7a0d94a5..19dca0f0a7 100644 --- a/game/src/info/intersection.rs +++ b/game/src/info/intersection.rs @@ -68,7 +68,13 @@ pub fn traffic( rows.push(throughput( ctx, app, - move |a| a.intersection_thruput.count_per_hour(id, time), + move |a| { + if a.intersection_thruput.raw.is_empty() { + a.intersection_thruput.count_per_hour(id, time) + } else { + a.intersection_thruput.raw_throughput(time, id) + } + }, &opts, )); diff --git a/game/src/info/lane.rs b/game/src/info/lane.rs index 8ccb783651..2366068bb4 100644 --- a/game/src/info/lane.rs +++ b/game/src/info/lane.rs @@ -188,7 +188,13 @@ pub fn traffic( rows.push(throughput( ctx, app, - move |a| a.road_thruput.count_per_hour(r, time), + move |a| { + if a.road_thruput.raw.is_empty() { + a.road_thruput.count_per_hour(r, time) + } else { + a.road_thruput.raw_throughput(time, r) + } + }, &opts, )); diff --git a/sim/src/analytics.rs b/sim/src/analytics.rs index 76059eedc6..f40c508a03 100644 --- a/sim/src/analytics.rs +++ b/sim/src/analytics.rs @@ -6,7 +6,7 @@ use map_model::{ Traversable, TurnGroupID, }; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; #[derive(Clone, Serialize, Deserialize)] pub struct Analytics { @@ -546,16 +546,26 @@ pub struct TripPhase { pub struct TimeSeriesCount { // (Road or intersection, mode, hour block) -> count for that hour pub counts: BTreeMap<(X, TripMode, usize), usize>, + + // Very expensive to store, so it's optional. But useful to flag on to experiment with + // representations better than the hour count above. + pub raw: Vec<(Time, TripMode, X)>, } impl TimeSeriesCount { fn new() -> TimeSeriesCount { TimeSeriesCount { counts: BTreeMap::new(), + raw: Vec::new(), } } fn record(&mut self, time: Time, id: X, mode: TripMode) { + // TODO Manually change flag + if false { + self.raw.push((time, mode, id.clone())); + } + let hour = time.get_parts().0; *self.counts.entry((id, mode, hour)).or_insert(0) += 1; } @@ -602,4 +612,70 @@ impl TimeSeriesCount { } results } + + pub fn raw_throughput(&self, now: Time, id: X) -> Vec<(TripMode, Vec<(Time, usize)>)> { + let window_size = Duration::hours(1); + let mut pts_per_mode: BTreeMap> = BTreeMap::new(); + let mut windows_per_mode: BTreeMap = BTreeMap::new(); + for mode in TripMode::all() { + pts_per_mode.insert(mode, vec![(Time::START_OF_DAY, 0)]); + windows_per_mode.insert(mode, Window::new(window_size)); + } + + for (t, m, x) in &self.raw { + if *x != id { + continue; + } + if *t > now { + break; + } + + let count = windows_per_mode.get_mut(m).unwrap().add(*t); + pts_per_mode.get_mut(m).unwrap().push((*t, count)); + } + + for (m, pts) in pts_per_mode.iter_mut() { + let mut window = windows_per_mode.remove(m).unwrap(); + + // Add a drop-off after window_size (+ a little epsilon!) + let t = (pts.last().unwrap().0 + window_size + Duration::seconds(0.1)).min(now); + if pts.last().unwrap().0 != t { + pts.push((t, window.count(t))); + } + + if pts.last().unwrap().0 != now { + pts.push((now, window.count(now))); + } + } + + pts_per_mode.into_iter().collect() + } +} + +struct Window { + times: VecDeque