学习需求
在用matsim实现交通流模拟drt场景时,遇到这样一个问题:车辆接送完乘客后,在没有新的订单之前,车辆一直停在最后一个停靠点上,这样车辆的利用率会较低,想实现一个送完最后一个乘客后,车辆能回到某个点上,在回到某个点的过程中响应新的订单?
调研目的
学习matsim在drt场景中是如何实现车辆的调度、任务的添加、更新以及调度状态的更新的?
调研笔记
1、车辆调度初始化
// 初始化车辆调度(初始时给车辆创建了一个StayTask任务)
DrtTaskFactory taskFactory = new DrtTaskFactoryImpl();
for (DvrpVehicle veh : fleet.getVehicles().values()) {veh.getSchedule().addTask(taskFactory.createStayTask(veh, veh.getServiceBeginTime(),veh.getServiceEndTime(), veh.getStartLink()));
}
可以发现车辆初始化时是创建了一个StayTask任务,添加到车辆调度任务列表中
2、调度中添加任务
//调度默认状态,添加新任务后变为PLANNED
private ScheduleStatus status = ScheduleStatus.UNPLANNED;
public void addTask(int taskIdx, Task task) {validateArgsBeforeAddingTask(taskIdx, task);if (status == ScheduleStatus.UNPLANNED) {status = ScheduleStatus.PLANNED;}AbstractTask t = (AbstractTask)task;tasks.add(taskIdx, t);t.taskIdx = taskIdx;t.status = TaskStatus.PLANNED;// update idx of the existing tasksfor (int i = taskIdx + 1; i < tasks.size(); i++) {tasks.get(i).taskIdx = i;}
}
这段Java代码是一个addTask方法的实现,是用于向某个任务计划中添加任务。以下是该方法的步骤和逻辑:参数验证:在添加任务之前,调用validateArgsBeforeAddingTask(taskIdx, task)方法来验证传入的参数是否有效。状态检查与更新:检查当前计划的状态(status)。如果状态是ScheduleStatus.UNPLANNED,则将其更新为ScheduleStatus.PLANNED。类型转换:将传入的task参数强制转换为AbstractTask类型。这表明task应该是AbstractTask的实例或其子类的实例。添加任务:将转换后的任务t插入到tasks列表的指定位置taskIdx。这里假设tasks是一个支持按索引添加元素的列表(如ArrayList)。设置任务索引:为新添加的任务t设置其索引taskIdx。设置任务状态:将新添加的任务状态设置为TaskStatus.PLANNED。更新现有任务索引:遍历tasks列表中taskIdx之后的所有任务,并将它们的索引设置为它们在列表中的位置。这是为了保持任务索引的连续性和正确性。这段代码假设了几个重要的类和枚举类型:AbstractTask:一个抽象类,实现了Task接口。
TaskStatus:一个枚举,表示任务的状态,enum TaskStatus {PLANNED, STARTED, PERFORMED}
ScheduleStatus:一个枚举,表示计划的状态,enum ScheduleStatus {UNPLANNED, PLANNED, STARTED, COMPLETED
}
tasks:一个列表,用于存储任务集合。
3、matsim中的任务类型
有三种任务:Stay、Drive、Stop
public class DrtTaskFactoryImpl implements DrtTaskFactory {@Overridepublic DrtDriveTask createDriveTask(DvrpVehicle vehicle, VrpPathWithTravelData path, DrtTaskType taskType) {return new DrtDriveTask(path, taskType);}@Overridepublic DrtStopTask createStopTask(DvrpVehicle vehicle, double beginTime, double endTime, Link link) {return new DefaultDrtStopTask(beginTime, endTime, link);}@Overridepublic DrtStayTask createStayTask(DvrpVehicle vehicle, double beginTime, double endTime, Link link) {return new DrtStayTask(beginTime, endTime, link);}
}
4、创建行驶任务
- 使用
taskFactory.createDriveTask
方法创建一个新的行驶任务(DrtDriveTask
)。这个方法需要车辆对象(vehicleEntry.vehicle
)、路径数据(vrpPath
)和任务类型(DrtDriveTask.TYPE
)。
下面为创建从停留或者停车任务的link到乘客请求的出发link的行驶任务,并添加到调度任务列表中
//根据起始link和结束link、路径、旅行时间创建vrpPath
VrpPathWithTravelData vrpPath = VrpPaths.createPath(stayOrStopTask.getLink(), request.getFromLink(),stayOrStopTask.getEndTime(), detourData.detourToPickup, travelTime);
//根据车辆、vrpPath、任务类型创建行驶任务
beforePickupTask = taskFactory.createDriveTask(vehicleEntry.vehicle, vrpPath, DrtDriveTask.TYPE);
//添加行驶任务到调度任务列表中
schedule.addTask(stayOrStopTask.getTaskIdx() + 1, beforePickupTask);
5、创建上客停车任务
使用taskFactory.createStopTask方法创建一个新的DrtStopTask上客停车任务。传入车辆、开始时间、计算出的停留时间与请求的最早开始时间中的较大者、以及上客点的link。
DrtStopTask pickupStopTask = taskFactory.createStopTask(vehicleEntry.vehicle, startTime,Math.max(startTime + stopDuration, request.getEarliestStartTime()), request.getFromLink());
schedule.addTask(taskIdx, pickupStopTask);