using failure crate in sim

This commit is contained in:
Dustin Carlino 2018-09-05 14:36:10 -07:00
parent a2c7b8b5bd
commit e99d9944e4
10 changed files with 62 additions and 62 deletions

View File

@ -20,6 +20,7 @@
what we're capable of. it might mask problems. but since things like
accel_to_stop_in_dist don't have a careful notion of how much time will pass,
they recommend big rates sometimes.
- no way for an agent to request a turn and ASAP have it granted. are there cases where they might slow down unnecessarily?
## bikes

View File

@ -811,10 +811,3 @@ It happens because a car was previously throttling itself due to somebody in
the way, but as soon as they start a turn, the car eagerly jumps ahead.
ah no, it's because we use max_lookahead_dist in accel_to_follow, and the speed limit we assert is the old road's speed.
## Peds warping bug
ped 60
goes from 631 (contraflow)
at least make sure that the turn they execute is the one on the correct side...

View File

@ -9,6 +9,7 @@ control = { path = "../control" }
derivative = "1.0.0"
dimensioned = { git = "https://github.com/paholg/dimensioned", rev = "0e1076ebfa5128d1ee544bdc9754c948987b6fe3", features = ["serde"] }
ezgui = { path = "../ezgui" }
failure = "0.1.2"
geom = { path = "../geom" }
map_model = { path = "../map_model" }
more-asserts = "0.2.1"

View File

@ -2,6 +2,7 @@ use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap};
use dimensioned::si;
use draw_car::DrawCar;
use failure::{Error, ResultExt};
use geom::EPSILON_DIST;
use intersections::{IntersectionSimState, Request};
use kinematics;
@ -84,7 +85,7 @@ impl Car {
transit_sim: &mut TransitSimState,
intersections: &IntersectionSimState,
properties: &BTreeMap<CarID, Vehicle>,
) -> Result<Action, InvariantViolated> {
) -> Result<Action, Error> {
if self.parking.is_some() {
// TODO right place for this check?
assert!(self.speed <= kinematics::EPSILON_SPEED);
@ -262,7 +263,7 @@ impl Car {
accel: Acceleration,
map: &Map,
intersections: &mut IntersectionSimState,
) -> Result<(), InvariantViolated> {
) -> Result<(), Error> {
let (dist, new_speed) = kinematics::results_of_accel_for_one_tick(self.speed, accel);
self.dist_along += dist;
self.speed = new_speed;
@ -270,7 +271,7 @@ impl Car {
loop {
let current_speed_limit = self.on.speed_limit(map);
if self.speed > current_speed_limit {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{} is going {} on {:?}, which has a speed limit of {}",
self.id, self.speed, self.on, current_speed_limit
)));
@ -305,15 +306,12 @@ impl Car {
self.waiting_for = None;
self.on = next_on;
if let On::Turn(t) = self.on {
// TODO easier way to attach more debug info?
intersections
.on_enter(Request::for_car(self.id, t))
.map_err(|e| {
InvariantViolated(format!(
"{}. new speed {}, leftover dist {}",
e, self.speed, leftover_dist
))
})?;
.context(format!(
"new speed {}, leftover dist {}",
self.speed, leftover_dist
))?;
}
self.dist_along = leftover_dist;
}
@ -359,13 +357,13 @@ impl SimQueue {
ids: &Vec<CarID>,
cars: &BTreeMap<CarID, Car>,
properties: &BTreeMap<CarID, Vehicle>,
) -> Result<(), InvariantViolated> {
) -> Result<(), Error> {
let old_queue = self.cars_queue.clone();
let new_queue: Vec<(Distance, CarID)> =
ids.iter().map(|id| (cars[id].dist_along, *id)).collect();
if new_queue.len() > self.capacity {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"on {:?}, reset to {:?} broke, because capacity is just {}.",
self.id, new_queue, self.capacity
)));
@ -381,7 +379,7 @@ impl SimQueue {
let ((dist1, c1), (dist2, c2)) = (slice[0], slice[1]);
let following_dist = properties[&c1].following_dist();
if dist1 - dist2 < following_dist {
return Err(InvariantViolated(format!("uh oh! on {:?}, reset to {:?} broke. min following distance is {}, but we have {} at {} and {} at {}. dist btwn is just {}. prev queue was {:?}", self.id, self.cars_queue, following_dist, c1, dist1, c2, dist2, dist1 - dist2, old_queue)));
bail!(InvariantViolated::new(format!("uh oh! on {:?}, reset to {:?} broke. min following distance is {}, but we have {} at {} and {} at {}. dist btwn is just {}. prev queue was {:?}", self.id, self.cars_queue, following_dist, c1, dist1, c2, dist2, dist1 - dist2, old_queue)));
}
}
Ok(())
@ -562,7 +560,7 @@ impl DrivingSimState {
transit_sim: &mut TransitSimState,
rng: &mut R,
properties: &BTreeMap<CarID, Vehicle>,
) -> Result<Vec<ParkedCar>, InvariantViolated> {
) -> Result<Vec<ParkedCar>, Error> {
self.populate_view(view);
// Could be concurrent, since this is deterministic -- EXCEPT for the rng, used to

View File

@ -5,6 +5,7 @@ use abstutil::{deserialize_btreemap, serialize_btreemap};
use control::stop_signs::{ControlStopSign, TurnPriority};
use control::ControlMap;
use dimensioned::si;
use failure::Error;
use kinematics;
use map_model::{IntersectionID, Map, TurnID};
use std::collections::{BTreeMap, BTreeSet};
@ -74,11 +75,11 @@ impl IntersectionSimState {
// MIGHT NOT be ready to enter the intersection (lookahead could send the request before the
// agent is the leader vehicle and at the end of the lane). The request may have been
// previously granted, but the agent might not have been able to start the turn.
pub fn submit_request(&mut self, req: Request) -> Result<(), InvariantViolated> {
pub fn submit_request(&mut self, req: Request) -> Result<(), Error> {
let i = self.intersections.get_mut(req.turn.parent.0).unwrap();
if let Some(t) = i.accepted().get(&req.agent) {
if *t != req.turn {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{:?} made, but {} has already been accepted",
req, t
)));
@ -120,7 +121,7 @@ impl IntersectionSimState {
}
}
pub fn on_enter(&self, req: Request) -> Result<(), InvariantViolated> {
pub fn on_enter(&self, req: Request) -> Result<(), Error> {
let id = req.turn.parent;
let i = &self.intersections[id.0];
if i.accepted().contains_key(&req.agent) {
@ -129,7 +130,7 @@ impl IntersectionSimState {
}
Ok(())
} else {
Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{:?} entered, but wasn't accepted by the intersection yet",
req
)))

View File

@ -1,4 +1,5 @@
use dimensioned::si;
use failure::Error;
use geom::EPSILON_DIST;
use rand::Rng;
use std;
@ -113,9 +114,9 @@ impl Vehicle {
&self,
speed: Speed,
dist: Distance,
) -> Result<Acceleration, InvariantViolated> {
) -> Result<Acceleration, Error> {
if dist < -EPSILON_DIST {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{} called accel_to_stop_in_dist({}, {}) with negative distance",
self.id, speed, dist
)));
@ -155,9 +156,9 @@ impl Vehicle {
&self,
current_speed: Speed,
speed_limit: Speed,
) -> Result<Distance, InvariantViolated> {
) -> Result<Distance, Error> {
if current_speed > speed_limit {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{} called max_lookahead_dist({}, {}) with current speed over the limit",
self.id, current_speed, speed_limit
)));
@ -170,13 +171,9 @@ impl Vehicle {
}
// TODO share with max_lookahead_dist
fn max_next_dist(
&self,
current_speed: Speed,
speed_limit: Speed,
) -> Result<Distance, InvariantViolated> {
fn max_next_dist(&self, current_speed: Speed, speed_limit: Speed) -> Result<Distance, Error> {
if current_speed > speed_limit {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{} called max_next_dist({}, {}) with current speed over the limit",
self.id, current_speed, speed_limit
)));
@ -214,7 +211,7 @@ impl Vehicle {
other: &Vehicle,
dist_behind_other: Distance,
other_speed: Speed,
) -> Result<Acceleration, InvariantViolated> {
) -> Result<Acceleration, Error> {
/* A seemingly failed attempt at a simpler version:
// What if they slam on their brakes right now?

View File

@ -6,6 +6,8 @@ extern crate control;
extern crate derivative;
extern crate dimensioned;
extern crate ezgui;
#[macro_use]
extern crate failure;
extern crate geom;
extern crate graphics;
extern crate map_model;
@ -44,7 +46,6 @@ use geom::{Angle, Pt2D};
pub use helpers::load;
use map_model::{LaneID, Map, TurnID};
pub use sim::{Benchmark, Sim};
use std::error;
use std::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -293,18 +294,17 @@ pub type Distance = si::Meter<f64>;
pub type Speed = si::MeterPerSecond<f64>;
pub type Acceleration = si::MeterPerSecond2<f64>;
#[derive(Debug)]
pub struct InvariantViolated(String);
impl error::Error for InvariantViolated {
fn description(&self) -> &str {
&self.0
}
// TODO enum of different cases? not really interesting to distinguish different proble, and it
// forces one central place to know lots of impl details
#[derive(Debug, Fail)]
#[fail(display = "{}", reason)]
pub struct InvariantViolated {
reason: String,
}
impl fmt::Display for InvariantViolated {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "InvariantViolated({0})", self.0)
impl InvariantViolated {
pub fn new(reason: String) -> InvariantViolated {
InvariantViolated { reason }
}
}

View File

@ -6,6 +6,7 @@ use dimensioned::si;
use draw_car::DrawCar;
use draw_ped::DrawPedestrian;
use driving::DrivingSimState;
use failure::Error;
use intersections::IntersectionSimState;
use kinematics::Vehicle;
use map_model::{IntersectionID, LaneID, LaneType, Map, Turn, TurnID};
@ -15,12 +16,13 @@ use spawn::Spawner;
use std;
use std::collections::BTreeMap;
use std::f64;
use std::process;
use std::time::{Duration, Instant};
use transit::TransitSimState;
use trips::TripManager;
use view::WorldView;
use walking::WalkingSimState;
use {AgentID, CarID, CarState, Event, InvariantViolated, PedestrianID, Tick, TIMESTEP};
use {AgentID, CarID, CarState, Event, PedestrianID, Tick, TIMESTEP};
#[derive(Serialize, Deserialize, Derivative)]
#[derivative(PartialEq, Eq)]
@ -122,20 +124,23 @@ impl Sim {
pub fn step(&mut self, map: &Map, control_map: &ControlMap) -> Vec<Event> {
match self.inner_step(map, control_map) {
Ok(events) => events,
Err(e) => panic!(
"At {}: {}\n\nDebug from {:?}",
self.time,
e,
self.find_most_recent_savestate()
),
Err(e) => {
// The order of causes is funky and backwards.
let mut causes: Vec<String> = e.iter_chain().map(|c| c.to_string()).collect();
causes.reverse();
println!("\nAt {}: {}", self.time, causes[0]);
for c in &causes[1..] {
println!(" {}", c);
}
if let Ok(s) = self.find_most_recent_savestate() {
println!("Debug from {}", s);
}
process::exit(1);
}
}
}
fn inner_step(
&mut self,
map: &Map,
control_map: &ControlMap,
) -> Result<(Vec<Event>), InvariantViolated> {
fn inner_step(&mut self, map: &Map, control_map: &ControlMap) -> Result<(Vec<Event>), Error> {
self.time = self.time.next();
let mut view = WorldView::new();

View File

@ -2,6 +2,7 @@ use abstutil;
use abstutil::{deserialize_multimap, serialize_multimap};
use dimensioned::si;
use draw_ped::DrawPedestrian;
use failure::Error;
use geom::{Line, Pt2D};
use intersections::{IntersectionSimState, Request};
use map_model::{BuildingID, BusStop, IntersectionID, Lane, LaneID, Map, Turn, TurnID};
@ -251,7 +252,7 @@ impl Pedestrian {
on: On,
map: &Map,
intersections: &mut IntersectionSimState,
) -> Result<(), InvariantViolated> {
) -> Result<(), Error> {
// Detect if the ped just warped. Bidirectional sidewalks are confusing. :)
if let On::Lane(l) = self.on {
let l = map.get_l(l);
@ -263,7 +264,7 @@ impl Pedestrian {
let pt2 = map.get_t(on.as_turn()).line.pt1();
let len = Line::new(pt1, pt2).length();
if len > 0.0 * si::M {
return Err(InvariantViolated(format!(
bail!(InvariantViolated::new(format!(
"{} just warped {}",
self.id, len
)));
@ -369,7 +370,7 @@ impl WalkingSimState {
delta_time: Time,
map: &Map,
intersections: &mut IntersectionSimState,
) -> Result<Vec<(PedestrianID, ParkingSpot)>, InvariantViolated> {
) -> Result<Vec<(PedestrianID, ParkingSpot)>, Error> {
// Could be concurrent, since this is deterministic.
let mut requested_moves: Vec<(PedestrianID, Action)> = Vec::new();
for p in self.peds.values() {

3
test_all.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
cargo test --release --no-fail-fast