diff --git a/rust_qsim/src/simulation/network/flow_cap.rs b/rust_qsim/src/simulation/network/flow_cap.rs
index 99e36131..ab5d4b60 100644
--- a/rust_qsim/src/simulation/network/flow_cap.rs
+++ b/rust_qsim/src/simulation/network/flow_cap.rs
@@ -18,6 +18,12 @@ impl Flowcap {
/**
Updates the accumulated capacity if the time has advanced.
*/
+ // TODO: Must know how many vehicles are in the buffer (see updateFastFlowAccumulation)
+
+ /// TODO:
+ /// The capacity of the buffer is the flowcapacityPerTimeStpe
+ /// Check if the accumalated flow capacity of the buffer is not exceeded.
+ /// Update flow capacity
pub fn update_capacity(&mut self, now: u32) {
if self.last_update_time < now {
let time_steps: f32 = (now - self.last_update_time) as f32;
diff --git a/rust_qsim/src/simulation/network/link.rs b/rust_qsim/src/simulation/network/link.rs
index 2cdb28c5..e698695e 100644
--- a/rust_qsim/src/simulation/network/link.rs
+++ b/rust_qsim/src/simulation/network/link.rs
@@ -114,6 +114,28 @@ impl SimLink {
}
}
+ /// This method pushes a vehicle directly into the buffer
+ pub fn push_veh_to_buffer(&mut self, vehicle: InternalVehicle, _now: u32) {
+ match self {
+ SimLink::Local(ll) => ll.push_veh_to_buffer(vehicle),
+ SimLink::In(il) => il.local_link.push_veh_to_buffer(vehicle),
+ SimLink::Out(_) => {
+ panic!("Can't push vehicle to buffer on out link")
+ }
+ }
+ }
+
+ /// This method pushes a vehicle to the waiting list, which has priority over vehicles in q
+ pub fn push_veh_to_waiting_list(&mut self, vehicle: InternalVehicle) {
+ match self {
+ SimLink::Local(ll) => ll.push_veh_to_waiting_list(vehicle),
+ SimLink::In(il) => il.local_link.push_veh_to_waiting_list(vehicle),
+ SimLink::Out(_) => {
+ panic!("Can't push vehicle to waiting list on out link")
+ }
+ }
+ }
+
pub fn pop_veh(&mut self) -> InternalVehicle {
match self {
SimLink::Local(ll) => ll.pop_front(),
@@ -149,6 +171,8 @@ impl SimLink {
pub struct LocalLink {
pub id: Id,
q: VecDeque,
+ buffer: VecDeque,
+ waiting_list: VecDeque,
length: f64,
free_speed: f32,
storage_cap: StorageCap,
@@ -183,6 +207,8 @@ impl LocalLink {
LocalLink {
id,
q: VecDeque::new(),
+ buffer: VecDeque::new(),
+ waiting_list: VecDeque::new(),
length: 1.0,
free_speed: 1.0,
storage_cap: StorageCap::new(0., 1., 1., 1.0, 7.5),
@@ -215,6 +241,8 @@ impl LocalLink {
LocalLink {
id,
q: VecDeque::new(),
+ buffer: VecDeque::new(),
+ waiting_list: VecDeque::new(),
length,
free_speed,
storage_cap,
@@ -238,12 +266,56 @@ impl LocalLink {
});
}
+ pub fn push_veh_to_buffer(&mut self, vehicle: InternalVehicle) {
+ // self.storage_cap.consume(vehicle.pce);
+ self.buffer.push_back(vehicle);
+ }
+
+ /// Push a vehicle into the waiting list.
+ pub fn push_veh_to_waiting_list(&mut self, vehicle: InternalVehicle) {
+ // self.storage_cap.consume(vehicle.pce);
+ self.waiting_list.push_back(vehicle);
+ }
+
+ /// This method fills the buffer from two sources with priority:
+ /// 1) Check if there are vehicles in the waiting list and move them to the buffer.
+ /// 2) Check if there are vehicles in the queue that have reached their earliest exit time and
+ /// move them to the buffer.
+ pub fn do_sim_step(&mut self, now: u32) {
+ self.update_flow_cap(now);
+ self.apply_storage_cap_updates();
+ self.add_waiting_to_buffer();
+ self.add_queue_to_buffer(now);
+ }
+
+ fn add_queue_to_buffer(&mut self, now: u32) {
+ while let Some(front) = self.q.front() {
+ if front.earliest_exit_time <= now {
+ //TODO check with self.flow_cap.has_capacity();
+ let veh = self.q.pop_front().unwrap().vehicle;
+ self.storage_cap.release(veh.pce);
+ self.buffer.push_back(veh);
+ } else {
+ break;
+ }
+ }
+ }
+
+ fn add_waiting_to_buffer(&mut self) {
+ while let Some(veh) = self.waiting_list.pop_front() {
+ self.buffer.push_back(veh);
+ }
+ }
+
+ /// This method returns the next/first vehicle from the buffer and removes it from the buffer.
pub fn pop_front(&mut self) -> InternalVehicle {
- let veh = self.q.pop_front().unwrap_or_else(|| panic!("There was no vehicle in the queue. Use 'offers_veh' to test if a vehicle is present first."));
- self.flow_cap.consume_capacity(veh.vehicle.pce);
- self.storage_cap.release(veh.vehicle.pce);
- self.stuck_timer.reset();
- veh.vehicle
+ if let Some(veh) = self.buffer.pop_front() {
+ // self.storage_cap.release(veh.pce);
+ self.flow_cap.consume_capacity(veh.pce);
+ self.stuck_timer.reset();
+ return veh;
+ }
+ panic!("There was no vehicle in the buffer.");
}
pub fn update_flow_cap(&mut self, now: u32) {
@@ -251,17 +323,13 @@ impl LocalLink {
self.flow_cap.update_capacity(now);
}
+ /// This method returns the next vehicle that is allowed to leave the connection and checks
+ /// whether flow capacity is available.
pub fn q_front(&self, now: u32) -> Option<&InternalVehicle> {
- // check if we have flow cap left for current time step, otherwise abort
- if !self.flow_cap.has_capacity() {
- return None;
- }
-
- // peek if fist vehicle in queue can leave
- if let Some(entry) = self.q.front() {
- if entry.earliest_exit_time <= now {
+ if let Some(entry) = self.buffer.front() {
+ if self.flow_cap.has_capacity() {
self.stuck_timer.start(now);
- return Some(&entry.vehicle);
+ return Some(entry);
}
}
diff --git a/rust_qsim/src/simulation/network/sim_network.rs b/rust_qsim/src/simulation/network/sim_network.rs
index 7e2eff25..f45ddf12 100644
--- a/rust_qsim/src/simulation/network/sim_network.rs
+++ b/rust_qsim/src/simulation/network/sim_network.rs
@@ -234,13 +234,21 @@ impl SimNetworkPartition {
);
});
+ // If events_publisher is None, this is the start of the route and the vehicle goes
+ // into the waiting list. `fill_buffer` prioritizes draining waiting_list into buffer.
+ let is_route_begin = events_publisher.is_none();
+
if let Some(publisher) = events_publisher {
publisher
.borrow_mut()
.publish_event(now, &Event::new_link_enter(link.id(), &vehicle.id));
}
- link.push_veh(vehicle, now);
+ if is_route_begin {
+ link.push_veh_to_waiting_list(vehicle);
+ } else {
+ link.push_veh(vehicle, now);
+ }
self.veh_counter += 1;
Self::activate_link(&mut self.active_links, link.id().clone());
@@ -292,8 +300,8 @@ impl SimNetworkPartition {
active_nodes: &mut IntSet>,
now: u32,
) -> bool {
- link.update_flow_cap(now);
- link.apply_storage_cap_updates();
+ // Move all vehicles that completed their link travel into the buffer.
+ link.do_sim_step(now);
// the node will only look at the vehicle at the at the top of the queue in the next timestep
// therefore, peek whether vehicles are available for the next timestep.
if link.q_front(now + 1).is_some() {