From 3488fb07e7538a02fbc57ec0aa9c54618dba9ac2 Mon Sep 17 00:00:00 2001 From: frievoe97 Date: Mon, 15 Sep 2025 11:24:55 +0200 Subject: [PATCH 1/4] added buffer and update order. vehicles move now from the q to the buffer --- rust_qsim/src/simulation/network/link.rs | 58 ++++++++++++++----- .../src/simulation/network/sim_network.rs | 13 ++++- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/rust_qsim/src/simulation/network/link.rs b/rust_qsim/src/simulation/network/link.rs index 2cdb28c5..21e0a2c3 100644 --- a/rust_qsim/src/simulation/network/link.rs +++ b/rust_qsim/src/simulation/network/link.rs @@ -114,6 +114,17 @@ 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") + } + } + } + pub fn pop_veh(&mut self) -> InternalVehicle { match self { SimLink::Local(ll) => ll.pop_front(), @@ -149,6 +160,7 @@ impl SimLink { pub struct LocalLink { pub id: Id, q: VecDeque, + buffer: VecDeque, length: f64, free_speed: f32, storage_cap: StorageCap, @@ -183,6 +195,7 @@ impl LocalLink { LocalLink { id, q: VecDeque::new(), + buffer: VecDeque::new(), length: 1.0, free_speed: 1.0, storage_cap: StorageCap::new(0., 1., 1., 1.0, 7.5), @@ -215,6 +228,7 @@ impl LocalLink { LocalLink { id, q: VecDeque::new(), + buffer: VecDeque::new(), length, free_speed, storage_cap, @@ -238,12 +252,32 @@ impl LocalLink { }); } + pub fn push_veh_to_buffer(&mut self, vehicle: InternalVehicle) { + self.storage_cap.consume(vehicle.pce); + self.buffer.push_back(vehicle); + } + + /// This method moves a vehicle from the q to the buffer if its earliest exit time is <= now. + pub fn fill_buffer(&mut self, now: u32) { + while let Some(front) = self.q.front() { + if front.earliest_exit_time <= now { + let veh = self.q.pop_front().unwrap().vehicle; + self.buffer.push_back(veh); + } else { + break; + } + } + } + + /// 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.flow_cap.consume_capacity(veh.pce); + self.storage_cap.release(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 +285,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..a26f41a8 100644 --- a/rust_qsim/src/simulation/network/sim_network.rs +++ b/rust_qsim/src/simulation/network/sim_network.rs @@ -234,13 +234,22 @@ impl SimNetworkPartition { ); }); + // If events_publisher is None, this is the start of the route and the vehicle drives + // directly into the buffer. + // TODO: Use Waiting List instead (next step) + 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_buffer(vehicle, now); + } else { + link.push_veh(vehicle, now); + } self.veh_counter += 1; Self::activate_link(&mut self.active_links, link.id().clone()); @@ -294,6 +303,8 @@ impl SimNetworkPartition { ) -> bool { link.update_flow_cap(now); link.apply_storage_cap_updates(); + // Move all vehicles that completed their link travel into the buffer. + link.fill_buffer(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() { From 3676f43497799e543184f2674fbe62718f1648b4 Mon Sep 17 00:00:00 2001 From: frievoe97 Date: Mon, 15 Sep 2025 11:33:27 +0200 Subject: [PATCH 2/4] start working on waitingList --- rust_qsim/src/simulation/network/link.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rust_qsim/src/simulation/network/link.rs b/rust_qsim/src/simulation/network/link.rs index 21e0a2c3..deef37a7 100644 --- a/rust_qsim/src/simulation/network/link.rs +++ b/rust_qsim/src/simulation/network/link.rs @@ -161,6 +161,7 @@ pub struct LocalLink { pub id: Id, q: VecDeque, buffer: VecDeque, + waiting_list: VecDeque, length: f64, free_speed: f32, storage_cap: StorageCap, @@ -196,6 +197,7 @@ impl 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), @@ -229,6 +231,7 @@ impl LocalLink { id, q: VecDeque::new(), buffer: VecDeque::new(), + waiting_list: VecDeque::new(), length, free_speed, storage_cap, From 15be1e2770c0f950dddb5f63786052e02ff74c55 Mon Sep 17 00:00:00 2001 From: frievoe97 Date: Mon, 15 Sep 2025 12:34:19 +0200 Subject: [PATCH 3/4] Implement waitingList. --- rust_qsim/src/simulation/network/link.rs | 25 ++++++++++++++++++- .../src/simulation/network/sim_network.rs | 7 +++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/rust_qsim/src/simulation/network/link.rs b/rust_qsim/src/simulation/network/link.rs index deef37a7..ef8fd17d 100644 --- a/rust_qsim/src/simulation/network/link.rs +++ b/rust_qsim/src/simulation/network/link.rs @@ -125,6 +125,17 @@ impl SimLink { } } + /// 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(), @@ -260,8 +271,20 @@ impl LocalLink { self.buffer.push_back(vehicle); } - /// This method moves a vehicle from the q to the buffer if its earliest exit time is <= now. + /// 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 fill_buffer(&mut self, now: u32) { + while let Some(veh) = self.waiting_list.pop_front() { + self.buffer.push_back(veh); + } while let Some(front) = self.q.front() { if front.earliest_exit_time <= now { let veh = self.q.pop_front().unwrap().vehicle; diff --git a/rust_qsim/src/simulation/network/sim_network.rs b/rust_qsim/src/simulation/network/sim_network.rs index a26f41a8..0c8b5dc7 100644 --- a/rust_qsim/src/simulation/network/sim_network.rs +++ b/rust_qsim/src/simulation/network/sim_network.rs @@ -234,9 +234,8 @@ impl SimNetworkPartition { ); }); - // If events_publisher is None, this is the start of the route and the vehicle drives - // directly into the buffer. - // TODO: Use Waiting List instead (next step) + // 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 { @@ -246,7 +245,7 @@ impl SimNetworkPartition { } if is_route_begin { - link.push_veh_to_buffer(vehicle, now); + link.push_veh_to_waiting_list(vehicle); } else { link.push_veh(vehicle, now); } From 75713f21701b62ed87574426c9653cedafb52598 Mon Sep 17 00:00:00 2001 From: frievoe97 Date: Mon, 15 Sep 2025 15:29:40 +0200 Subject: [PATCH 4/4] start working on flowcapacity in combination with the buffer --- rust_qsim/src/simulation/network/flow_cap.rs | 6 +++++ rust_qsim/src/simulation/network/link.rs | 26 ++++++++++++++----- .../src/simulation/network/sim_network.rs | 4 +-- 3 files changed, 26 insertions(+), 10 deletions(-) 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 ef8fd17d..e698695e 100644 --- a/rust_qsim/src/simulation/network/link.rs +++ b/rust_qsim/src/simulation/network/link.rs @@ -267,13 +267,13 @@ impl LocalLink { } pub fn push_veh_to_buffer(&mut self, vehicle: InternalVehicle) { - self.storage_cap.consume(vehicle.pce); + // 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.storage_cap.consume(vehicle.pce); self.waiting_list.push_back(vehicle); } @@ -281,13 +281,19 @@ impl LocalLink { /// 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 fill_buffer(&mut self, now: u32) { - while let Some(veh) = self.waiting_list.pop_front() { - self.buffer.push_back(veh); - } + 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; @@ -295,11 +301,17 @@ impl LocalLink { } } + 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 { if let Some(veh) = self.buffer.pop_front() { + // self.storage_cap.release(veh.pce); self.flow_cap.consume_capacity(veh.pce); - self.storage_cap.release(veh.pce); self.stuck_timer.reset(); return veh; } diff --git a/rust_qsim/src/simulation/network/sim_network.rs b/rust_qsim/src/simulation/network/sim_network.rs index 0c8b5dc7..f45ddf12 100644 --- a/rust_qsim/src/simulation/network/sim_network.rs +++ b/rust_qsim/src/simulation/network/sim_network.rs @@ -300,10 +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.fill_buffer(now); + 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() {