mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 04:35:51 +03:00
using failure crate in sim
This commit is contained in:
parent
a2c7b8b5bd
commit
e99d9944e4
@ -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
|
||||
|
||||
|
@ -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...
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)))
|
||||
|
@ -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?
|
||||
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
3
test_all.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
cargo test --release --no-fail-fast
|
Loading…
Reference in New Issue
Block a user