当前位置: 首页 > 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系统中如何根据当前车辆状态和请求要求,安排新的上客任务,并相应地更新车辆的行程。代码中包含了多个条件分支和异常处理,确保了在不同情况下都能正确安排任务。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 安利7个免费开源的网络监控工具(非常详细)收藏这一篇就够了
  • 调研-音视频
  • T/CECS 10035-2019 绿色建材评价 金属复合装饰材料
  • 数字赋能下的艺术蝶变:沃可趣如何重塑乐园演艺人才培训?
  • js中filter函数使用箭头函数的时候注意事项
  • 基于x86 平台opencv的图像采集和seetaface6的静默活体功能
  • H5实现带电话号码跳转到手机呼叫
  • Java二十三种设计模式-状态模式(20/23)
  • uniapp微信小程序 分享功能
  • Python计算机视觉编程 第六章
  • MySQL 视图(VIEW)的使用
  • AI在医学领域:HYDEN一种针对医学图像和报告的跨模态表示学习方法
  • IOS 13 网络请求和Moya框架
  • k8s高版本(1,28)部署NodePort模式下的ingress-nginx的详细过程及应用案例
  • 图片转pdf:tif是什么格式?如何将tif转成PDF?
  • 3.7、@ResponseBody 和 @RestController
  • Apache Spark Streaming 使用实例
  • create-react-app做的留言板
  • Fundebug计费标准解释:事件数是如何定义的?
  • JavaScript/HTML5图表开发工具JavaScript Charts v3.19.6发布【附下载】
  • JavaScript服务器推送技术之 WebSocket
  • MySQL用户中的%到底包不包括localhost?
  • php面试题 汇集2
  • Python - 闭包Closure
  • Spring Cloud Feign的两种使用姿势
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Vue.js 移动端适配之 vw 解决方案
  • 程序员该如何有效的找工作?
  • 从tcpdump抓包看TCP/IP协议
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 浅谈Golang中select的用法
  • 通过npm或yarn自动生成vue组件
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​一些不规范的GTID使用场景
  • #WEB前端(HTML属性)
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • (C++哈希表01)
  • (Python) SOAP Web Service (HTTP POST)
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (笔试题)合法字符串
  • (独孤九剑)--文件系统
  • (二)Linux——Linux常用指令
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (六)激光线扫描-三维重建
  • (四)Android布局类型(线性布局LinearLayout)
  • (转)jdk与jre的区别
  • *** 2003
  • .NET 8 中引入新的 IHostedLifecycleService 接口 实现定时任务
  • .Net FrameWork总结
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .net/c# memcached 获取所有缓存键(keys)
  • .net8.0与halcon编程环境构建