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() {