From 8cc61aafc8433c8575687a8fe2851a73aa68d2fe Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 9 Sep 2020 19:52:15 -0700 Subject: [PATCH] Add a method to the API to modify a scenario. No callers/tests yet. --- book/src/dev/api.md | 3 +++ headless/src/main.rs | 13 +++++++++++-- sim/src/make/load.rs | 17 ++++++++++++++--- sim/src/make/modifier.rs | 3 ++- sim/src/sim.rs | 6 ++++++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/book/src/dev/api.md b/book/src/dev/api.md index 908b32b66d..b8f69e62ef 100644 --- a/book/src/dev/api.md +++ b/book/src/dev/api.md @@ -23,6 +23,9 @@ are missing, etc. A summary of the commands available so far: - **GET /sim/reset**: Reset all map edits and the simulation state. The trips that will run don't change; they're determined by the scenario file you initially pass to `headless`. + - **POST /sim/load**: Switch the scenario being simulated. Takes a + [SimFlags](https://dabreegster.github.io/abstreet/rustdoc/sim/struct.SimFlags.html) + as a JSON POST body. - **GET /sim/get-time**: Returns the current simulation time. - **GET /sim/goto-time?t=06:30:00**: Simulate until 6:30 AM. If the time you specify is before the current time, you have to call **/sim/reset** first. diff --git a/headless/src/main.rs b/headless/src/main.rs index 1950977de3..c943edbc2d 100644 --- a/headless/src/main.rs +++ b/headless/src/main.rs @@ -29,7 +29,6 @@ use std::sync::RwLock; lazy_static::lazy_static! { static ref MAP: RwLock = RwLock::new(Map::blank()); static ref SIM: RwLock = RwLock::new(Sim::new(&Map::blank(), SimOptions::new("tmp"), &mut Timer::throwaway())); - // TODO Readonly? static ref FLAGS: RwLock = RwLock::new(SimFlags::for_test("tmp")); } @@ -98,6 +97,16 @@ fn handle_command( *sim = new_sim; Ok(format!("sim reloaded")) } + "/sim/load" => { + let flags: SimFlags = abstutil::from_json(body)?; + *FLAGS.write().unwrap() = flags; + + // Also reset + let (new_map, new_sim, _) = FLAGS.read().unwrap().load(&mut Timer::new("reset sim")); + *map = new_map; + *sim = new_sim; + Ok(format!("flags changed and sim reloaded")) + } "/sim/get-time" => Ok(sim.time().to_string()), "/sim/goto-time" => { let t = Time::parse(¶ms["t"])?; @@ -126,7 +135,7 @@ fn handle_command( scenario.people = ExternalPerson::import(map, vec![input])?; let id = PersonID(sim.get_all_people().len()); scenario.people[0].id = id; - let mut rng = SimFlags::for_test("oneshot").make_rng(); + let mut rng = FLAGS.read().unwrap().make_rng(); scenario.instantiate(sim, map, &mut rng, &mut Timer::throwaway()); Ok(format!("{} created", id)) } diff --git a/sim/src/make/load.rs b/sim/src/make/load.rs index af2463af2d..1cc3516c88 100644 --- a/sim/src/make/load.rs +++ b/sim/src/make/load.rs @@ -1,15 +1,19 @@ -use crate::{AlertHandler, Scenario, Sim, SimOptions}; +use crate::{AlertHandler, Scenario, ScenarioModifier, Sim, SimOptions}; use abstutil::CmdArgs; use map_model::{Map, MapEdits}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; +use serde::Deserialize; const RNG_SEED: u8 = 42; -#[derive(Clone)] +#[derive(Clone, Deserialize)] pub struct SimFlags { pub load: String, + pub modifiers: Vec, + #[serde(skip_deserializing)] pub rng_seed: u8, + #[serde(skip_deserializing)] pub opts: SimOptions, } @@ -23,6 +27,7 @@ impl SimFlags { load: args .optional_free() .unwrap_or_else(|| abstutil::path_map("montlake")), + modifiers: Vec::new(), rng_seed, opts: SimOptions { run_name: args @@ -61,6 +66,7 @@ impl SimFlags { pub fn synthetic_test(map: &str, run_name: &str) -> SimFlags { SimFlags { load: abstutil::path_map(map), + modifiers: Vec::new(), rng_seed: RNG_SEED, opts: SimOptions::new(run_name), } @@ -103,10 +109,15 @@ impl SimFlags { self.load )); - let scenario: Scenario = abstutil::read_binary(self.load.clone(), timer); + let mut scenario: Scenario = abstutil::read_binary(self.load.clone(), timer); let map = Map::new(abstutil::path_map(&scenario.map_name), timer); + let mut modifier_rng = self.make_rng(); + for m in &self.modifiers { + scenario = m.apply(&map, scenario, &mut modifier_rng); + } + if opts.run_name == "unnamed" { opts.run_name = scenario.scenario_name.clone(); } diff --git a/sim/src/make/modifier.rs b/sim/src/make/modifier.rs index 38fada9ff4..20e1c2bc03 100644 --- a/sim/src/make/modifier.rs +++ b/sim/src/make/modifier.rs @@ -4,9 +4,10 @@ use geom::{Duration, Time}; use map_model::Map; use rand::Rng; use rand_xorshift::XorShiftRng; +use serde::Deserialize; use std::collections::BTreeSet; -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize)] pub enum ScenarioModifier { RepeatDays(usize), CancelPeople(usize), diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 0d15e7d5be..60292ee5b7 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -76,6 +76,12 @@ pub struct SimOptions { pub live_map_edits: bool, } +impl std::default::Default for SimOptions { + fn default() -> SimOptions { + SimOptions::new("tmp") + } +} + #[derive(Clone)] pub enum AlertHandler { // Just print the alert to STDOUT