当前位置: 首页 > news >正文

[Matsim]Matsim学习笔记-动态线路接乘客上车的逻辑

学习需求

matsim中动态线路场景模拟中核心的是三个功能:
1、拼车,生成新的插入点
2、生成接乘客上车的任务
3、生成送乘客下车的任务
本次学习第2个功能:接乘客上车的任务

学习笔记

接乘客上车在matsim中的代码是在扩展包

org.matsim.contrib.drt.scheduler

今天学习默认的调度器

DefaultRequestInsertionScheduler

接乘客上车的方法

var pickupTask = insertPickup(request, insertion);

下面是对insertPickUp方法的代码分析

insertPickUp

输入参数:
request:当前应答成功的订单请求
insertion:当前应答成功的订单的插入对象
输出结果
drtStopTask:接当前乘客的停车任务
源代码:

//用于在DVRP或DRT系统中安排一个上客任务(返回接乘客上车前的stopTask,即停车接乘客上车的任务)
DrtStopTask insertPickup(AcceptedDrtRequest request, InsertionWithDetourData insertionWithDetourData) {//当前订单的插入点,包含在哪上车,在哪下车var insertion = insertionWithDetourData.insertion;//当前订单的车辆VehicleEntry vehicleEntry = insertion.vehicleEntry;//当前订单的车辆的调度Schedule schedule = vehicleEntry.vehicle.getSchedule();//当前车辆的停靠点List<Waypoint.Stop> stops = vehicleEntry.stops;int pickupIdx = insertion.pickup.index;int dropoffIdx = insertion.dropoff.index;//绕路信息var detourData = insertionWithDetourData.detourData;//根据行程的当前状态scheduleStatus,确定是否需要创建新的上客任务ScheduleStatus scheduleStatus = schedule.getStatus();Task currentTask = scheduleStatus == ScheduleStatus.PLANNED ? null : schedule.getCurrentTask();//接乘客之前的任务Task beforePickupTask;//***************处理已经开始的行程****************************////如果行程已经开始并且当前任务是上客或下客任务,//找当前路径的改道点,如果找到改道点,重新规划路径//如果没有找到改造点,则会创建一个新的行驶任务。if (pickupIdx == 0 && scheduleStatus != ScheduleStatus.PLANNED && DRIVE.isBaseTypeOf(currentTask)) {LinkTimePair diversion = ((OnlineDriveTaskTracker)currentTask.getTaskTracker()).getDiversionPoint();if (diversion != null) { // divert vehiclebeforePickupTask = currentTask;VrpPathWithTravelData vrpPath = VrpPaths.createPath(vehicleEntry.start.link, request.getFromLink(),vehicleEntry.start.time, detourData.detourToPickup, travelTime);((OnlineDriveTaskTracker)beforePickupTask.getTaskTracker()).divertPath(vrpPath);} else { // too late for diversionif (request.getFromLink() != vehicleEntry.start.link) { // add a new drive taskVrpPathWithTravelData vrpPath = VrpPaths.createPath(vehicleEntry.start.link, request.getFromLink(),vehicleEntry.start.time, detourData.detourToPickup, travelTime);beforePickupTask = taskFactory.createDriveTask(vehicleEntry.vehicle, vrpPath, DrtDriveTask.TYPE);schedule.addTask(currentTask.getTaskIdx() + 1, beforePickupTask);} else { // no need for a new drive taskbeforePickupTask = currentTask;}}} else { // 如果行程已经开始并且当前任务是停留任务,会根据当前时间和请求的最早开始时间调整停留任务的结束时间DrtStayTask stayTask = null;DrtStopTask stopTask = null;if (pickupIdx == 0) {if (scheduleStatus == ScheduleStatus.PLANNED) {// PLANNED  表示车辆当前没有进行中的任务//从行程中获取第一个停留任务(DrtStayTask),初始化时的stay任务stayTask = (DrtStayTask)schedule.getTasks().get(0);//将停留任务的结束时间设置为其开始时间,这意味着停留任务将立即结束stayTask.setEndTime(stayTask.getBeginTime());} else if (STAY.isBaseTypeOf(currentTask)) {//中间过程中的持续进行的stay任务stayTask = (DrtStayTask)currentTask; double now = timer.getTimeOfDay();//如果停留任务的结束时间大于当前时间,将停留任务的结束时间设置为当前时间,这样新的任务就可以插入。if (stayTask.getEndTime() > now) { stayTask.setEndTime(now);}} else {//处理正在进行中的停车任务stopTask = (DrtStopTask)currentTask; }} else {//处理非第一个任务的上客stopTask = stops.get(pickupIdx - 1).task; }if (stopTask != null && request.getFromLink() == stopTask.getLink()) { // no detour; no new stop task// add pickup request to stop taskstopTask.addPickupRequest(request);double stopDuration = stopDurationEstimator.calcDuration(vehicleEntry.vehicle, stopTask.getDropoffRequests().values(), stopTask.getPickupRequests().values());stopTask.setEndTime(Math.max(stopTask.getBeginTime() + stopDuration, request.getEarliestStartTime()));if (pickupIdx == dropoffIdx) {// remove drive i->i+1 (if there is one)if (pickupIdx < stops.size()) {// there is at least one following stopDrtStopTask nextStopTask = stops.get(pickupIdx).task;if (stopTask.getTaskIdx() + 2 != nextStopTask.getTaskIdx()) {// there must a drive task in// betweenthrow new RuntimeException();}if (stopTask.getTaskIdx() + 2 == nextStopTask.getTaskIdx()) {// there must a drive task in// betweenint driveTaskIdx = stopTask.getTaskIdx() + 1;schedule.removeTask(schedule.getTasks().get(driveTaskIdx));}}Link toLink = request.getToLink(); // pickup->dropoffVrpPathWithTravelData vrpPath = VrpPaths.createPath(request.getFromLink(), toLink,stopTask.getEndTime(), detourData.detourFromPickup, travelTime);Task driveFromPickupTask = taskFactory.createDriveTask(vehicleEntry.vehicle, vrpPath,DrtDriveTask.TYPE);schedule.addTask(stopTask.getTaskIdx() + 1, driveFromPickupTask);// 更新后续任务的开始和结束时间scheduleTimingUpdater.updateTimingsStartingFromTaskIdx(vehicleEntry.vehicle,stopTask.getTaskIdx() + 2, driveFromPickupTask.getEndTime());}return stopTask;} else {StayTask stayOrStopTask = stayTask != null ? stayTask : stopTask;//检查是否有后续停车点	// remove drive i->i+1 (if there is one)if (pickupIdx < stops.size()) {// there is at least one following stop//获取下一个停车任务DrtStopTask nextStopTask = stops.get(pickupIdx).task;// check: if there is at most one drive task in betweenif (stayOrStopTask.getTaskIdx() + 2 != nextStopTask.getTaskIdx() //&& stayTask != null && stayTask.getTaskIdx() + 1 != nextStopTask.getTaskIdx()) {throw new RuntimeException();}//检查是否有行驶任务需要移除 if (stayOrStopTask.getTaskIdx() + 2 == nextStopTask.getTaskIdx()) {// removing the drive task that is in betweenint driveTaskIdx = stayOrStopTask.getTaskIdx() + 1;//移除中间的行驶任务schedule.removeTask(schedule.getTasks().get(driveTaskIdx));}}//处理两种情况:一种是车辆已经在上客点(无需额外行驶),另一种是车辆需要行驶到上客点。if (stayTask != null && request.getFromLink() == stayTask.getLink()) {// the bus stays where it isbeforePickupTask = stayTask;} else {// add drive task to pickup location// insert drive i->pickup// 需要创建一个新的行驶任务以将车辆从当前位置行驶到上客点VrpPathWithTravelData vrpPath = VrpPaths.createPath(stayOrStopTask.getLink(), request.getFromLink(),stayOrStopTask.getEndTime(), detourData.detourToPickup, travelTime);beforePickupTask = taskFactory.createDriveTask(vehicleEntry.vehicle, vrpPath, DrtDriveTask.TYPE);schedule.addTask(stayOrStopTask.getTaskIdx() + 1, beforePickupTask);}}}// insert pickup stop taskdouble startTime = beforePickupTask.getEndTime();int taskIdx = beforePickupTask.getTaskIdx() + 1;double stopDuration = stopDurationEstimator.calcDuration(vehicleEntry.vehicle, Collections.emptySet(), Collections.singleton(request));DrtStopTask pickupStopTask = taskFactory.createStopTask(vehicleEntry.vehicle, startTime,Math.max(startTime + stopDuration, request.getEarliestStartTime()), request.getFromLink());schedule.addTask(taskIdx, pickupStopTask);pickupStopTask.addPickupRequest(request);// add drive from pickupLink toLink = pickupIdx == dropoffIdx ? request.getToLink() // pickup->dropoff: stops.get(pickupIdx).task.getLink(); // pickup->i+1VrpPathWithTravelData vrpPath = VrpPaths.createPath(request.getFromLink(), toLink, pickupStopTask.getEndTime(),detourData.detourFromPickup, travelTime);Task driveFromPickupTask = taskFactory.createDriveTask(vehicleEntry.vehicle, vrpPath, DrtDriveTask.TYPE);schedule.addTask(taskIdx + 1, driveFromPickupTask);// update timingsscheduleTimingUpdater.updateTimingsStartingFromTaskIdx(vehicleEntry.vehicle, taskIdx + 2,driveFromPickupTask.getEndTime());return pickupStopTask;
}

代码的整体逻辑
insertPickup用于在DVRP或DRT系统中安排一个上客任务。这个方法相当复杂,涉及多个步骤和条件判断,以下是它的逻辑概述:

上客逻辑
  1. 提取参数:从方法参数中提取插入数据insertionWithDetourData和请求request

  2. 获取车辆信息:从插入数据中获取VehicleEntry对象,进而获取车辆的行程schedule和停车点列表stops

  3. 确定上客索引和绕路数据:从插入数据中获取上客的索引pickupIdx和绕路数据detourData

  4. 检查行程状态:根据行程的当前状态scheduleStatus,确定是否需要创建新的上客任务。

  5. 处理已经开始的行程

    • 如果行程已经开始并且当前任务是上客或下客任务,并且车辆可以改道,那么会创建一个改道任务。
    • 如果行程已经开始并且当前任务是停留任务,会根据当前时间和请求的最早开始时间调整停留任务的结束时间。
  6. 创建上客任务

    • 如果上客点与当前任务或停留任务的地点相同,不需要创建新的上客任务,而是将请求添加到现有任务。
    • 如果需要创建新的上客任务,会计算开始时间并使用taskFactory创建一个新的DrtStopTask
  7. 添加上客请求:将接受的DRT请求添加到相应的上客任务。

  8. 创建从上客点出发的行驶任务:计算从上客点到下一个目的地的路径,并创建一个新的行驶任务。

  9. 更新行程:将新创建的上客任务和行驶任务添加到行程中。

  10. 更新时间:调用scheduleTimingUpdater更新行程中的任务时间。

  11. 返回结果:方法返回创建的DrtStopTask上客任务。

    关键点解释:

    • AcceptedDrtRequest:代表已接受的DRT请求。
    • InsertionWithDetourData:包含有关任务插入和绕路时间的数据结构。
    • VehicleEntry:包含车辆信息和停车点列表的数据结构。
    • Schedule:代表车辆行程的类。
    • Task:代表行程中的任务,可以是行驶任务、停留任务或上/下客任务。
    • DrtStopTask:特定类型的任务,代表DRT中的上客或下客任务。
    • taskFactory:用于创建任务的工厂类。
    • scheduleTimingUpdater:用于更新行程时间的类。

    这段代码展示了在DRT系统中如何根据当前车辆状态和请求要求,安排新的上客任务,并相应地更新车辆的行程。代码中包含了多个条件分支和异常处理,确保了在不同情况下都能正确安排任务。


http://www.mrgr.cn/news/11835.html

相关文章:

  • 网络UDP报文详细解析
  • 80、k8s概念及组件介绍
  • 网络 (tcp)
  • windows中使用vscode的remote-ssh连接linux失败
  • AR 眼镜之-系统应用音效-实现方案
  • 11. HashSet的内部实现原理是什么?它如何保证元素不重复?
  • SSRF漏洞——pikachu
  • Excel中使用VBS自定义函数将中文转为拼音首字母
  • 浙商之源——龙游商帮丨龙游商帮的具象文化符号之建筑篇
  • QtWebEngineView加载本地网页
  • Linux项目自动化构建工具-make/Makefile
  • Java共享内容通信 VS Golang通信共享内存
  • 数据结构---顺序表---单链表
  • 93.WEB渗透测试-信息收集-Google语法(7)
  • 小琳AI课堂:生成对抗网络(GANs)
  • Spring security 密码加密使用
  • 数据结构-递归算法-第四天
  • 苹果发布iOS 18 Beta 7更新:RC准正式版正在路上
  • 论文《Graph Structural Attack by Perturbing Spectral Distance》笔记
  • ReadAgent,一款具有要点记忆的人工智能阅读代理