This commit is contained in:
DU 2021-01-26 16:21:45 +08:00
commit bf3bf28fad
10 changed files with 323 additions and 33 deletions

View File

@ -26,6 +26,8 @@ public enum Project {
DRTS,
/** 北京交通大学项目(客流量科研) */
BJD,
/** 成都工业职业技术学院 */
CGY,
;
public static boolean isDefault(Project project) {

View File

@ -9,8 +9,10 @@ public final class Config {
public static final int STAND_MAX_STOP_TIME = 90;
/** 列车最大容量 */
public static final int TRAIN_CAPACITY = 1500;
/** 站台无效的上车时间开关门6s+下车4s+发车前确认5s */
public static final int INVALID_BOARD_TIME = 15;
/** 站台乘客上列车速度: 人/秒 (列车停站上车时间应该是总停站时间-开关门6s+下车4s+发车前确认5s) */
public static final float PASSENGER_ON_SPEED = 12;
public static final float PASSENGER_BOARD_SPEED = 12;
/** 列车跳停节省时间,单位 - 秒 */
public static final int TRAIN_PASS_SAVE_TIME = 60;
}

View File

@ -13,6 +13,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -51,9 +52,11 @@ public class LargePassengerFlowStrategyService {
private StrategyCalculateData buildStrategyCalculateData(PassengerFlowSimulationData passengerFlowSimulationData) {
Simulation simulation = this.passengerFlowSimulateService.getSimulationByGroup(passengerFlowSimulationData.getGroup());
LocalDateTime systemTime = simulation.getSystemTime();
SimulationDataRepository repository = simulation.getRepository();
Map<String, List<TripPlan>> serviceTripsMap = repository.getServiceTripsMap();
StrategyCalculateData strategyCalculateData = new StrategyCalculateData(
systemTime,
serviceTripsMap,
repository.getRealRunRecordList(),
passengerFlowSimulationData.getAllStandPassengerFlow(),

View File

@ -1,14 +1,181 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.Strategy;
import club.joylink.rtss.exception.BusinessExceptionAssertEnum;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.ParkTimeStrategy;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StandPassenger;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StrategyCalculateData;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.TrainPassenger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalTime;
import java.util.*;
@Slf4j
@Component
public class ParkTimeStrategyServiceImpl implements StrategyService {
public class ParkTimeStrategyServiceImpl implements StrategyService<ParkTimeStrategy> {
@Override
public Strategy calculate(StrategyCalculateData data) {
public List<ParkTimeStrategy> generateStrategy(StrategyCalculateData data) {
List<ParkTimeStrategy> list = new ArrayList<>();
Stand stand = null;
// 暂时按一个站大客流处理
List<StandPassenger> standPassengerList = data.getAllStandPassengerList();
for (StandPassenger standPassenger : standPassengerList) {
if (standPassenger.isLpf()) {
stand = standPassenger.getStand();
break;
}
}
if (stand == null) {
return null;
}
Map<String, List<TripPlan>> planMap = data.getPlanMap();
int planParkTime = 0; // 计划停站时间
for (List<TripPlan> planList : planMap.values()) {
for (TripPlan tripPlan : planList) {
List<StationPlan> stationPlanList = tripPlan.getPlanList();
for (StationPlan stationPlan : stationPlanList) {
if (Objects.equals(stationPlan.getSection(), stand.getSection()) &&
stationPlan.getParkTime() > 0) {
planParkTime = stationPlan.getParkTime();
break;
}
}
}
if (planParkTime > 0) {
break;
}
}
if (planParkTime <= 0) {
throw new IllegalArgumentException(String.format("计划或站台[%s]数据异常,找到的计划停站时间异常:为[%s]", stand.debugStr(), planParkTime));
}
// 最大停站时间内每隔5秒生成一个策略策略的停站时间为计划停站时间+5*i
int iter = (Config.STAND_MAX_STOP_TIME - planParkTime) / 5;
for (int i = 1; i <= iter; i++) {
list.add(new ParkTimeStrategy(stand, planParkTime + i * 5));
}
log.debug(String.format("生成增大停站时间策略[%s]个", list.size()));
return list;
}
@Override
public void calculate(StrategyCalculateData data, ParkTimeStrategy strategy) {
Stand stand = strategy.getStand();
Integer parkTime = strategy.getTime();
// 系统时间
LocalTime systemTime = data.getSystemTime().toLocalTime();// 系统当前时间
LocalTime endTime = systemTime.plusMinutes(Config.STRATEGY_CAL_TIME);// 预测计算终点
LocalTime nextTime = systemTime;
int target1 = 0;
int target2 = 0;
List<TrainPassenger> trainPassengerList = data.getTrainPassengerList();
Map<String, RealRun> trainPreviousMap = new HashMap<>(); // 列车上一个到站/发车数据
while (systemTime.isBefore(endTime)) { // 在计算时间内
for (TrainPassenger trainPassenger : trainPassengerList) {
String groupNumber = trainPassenger.getGroupNumber();
TripPlan tripPlan = data.queryTripPlan(trainPassenger.getServiceNumber(), trainPassenger.getTripNumber());
if (tripPlan == null) { // 未找到计划跳过
log.warn(String.format("列车[%s-%s|%s]没有找到车次计划",
groupNumber, trainPassenger.getServiceNumber(), trainPassenger.getTripNumber()));
continue;
}
if (tripPlan.isBackup()) {
continue;
}
// 上一实际到发
RealRun realRun = trainPreviousMap.get(groupNumber);
if (realRun == null) {
realRun = data.queryPreviousRealRunData(groupNumber);
if (realRun != null) {
trainPreviousMap.put(groupNumber, realRun);
}
}
List<StationPlan> planList = tripPlan.getPlanList();
int offsetTime = 0;
StationPlan nextStationPlan = null;
if (realRun != null &&
Objects.equals(tripPlan.getServiceNumber(), realRun.getServiceNumber()) &&
Objects.equals(tripPlan.getTripNumber(), realRun.getTripNumber())) {
// 上一实际运行数据存在且在当前计划中
// 查询实际运行到的车站计划
StationPlan stationPlan = tripPlan.queryStationPlanByStationCode(realRun.getStationCode());
BusinessExceptionAssertEnum.DATA_ERROR.assertNotNull(stationPlan);
LocalTime leaveTime = stationPlan.getLeaveTime();
if (realRun.isArrive()) {
// 是到达车站的计划预测离站
LocalTime arriveTime = stationPlan.getArriveTime();
if (!tripPlan.isFirstPlan(stationPlan)) {
offsetTime = realRun.getTime().toLocalTime().toSecondOfDay() - arriveTime.toSecondOfDay();
}
RealRun leave = this.handleTrainLeave(data, strategy, trainPassenger, tripPlan, stationPlan, offsetTime);
trainPreviousMap.put(groupNumber, leave);
if (leave.getTime().toLocalTime().isBefore(nextTime)) {
nextTime = leave.getTime().toLocalTime();
}
} else {
offsetTime = realRun.getTime().toLocalTime().toSecondOfDay() - leaveTime.toSecondOfDay();
}
if (tripPlan.isLastPlan(stationPlan)) {
// 最后一个到发计划获取下一个折返后车次计划
TripPlan nextTripPlan = data.queryNextTripPlan(tripPlan);
if (nextTripPlan != null) {
tripPlan = nextTripPlan;
nextStationPlan = nextTripPlan.getFirstStationPlan();
}
} else {
nextStationPlan = tripPlan.queryNextStationPlanByStationCode(realRun.getStationCode());
}
} else {
for (StationPlan stationPlan : planList) {
if (stationPlan.getArriveTime().compareTo(systemTime) >= 0) {
nextStationPlan = stationPlan;
break;
}
}
}
if (nextStationPlan != null) {
LocalTime arriveTime = nextStationPlan.getArriveTime();
RealRun arrive = this.buildRealRun(groupNumber, tripPlan, nextStationPlan, true, arriveTime, offsetTime, data.getSystemTime());
data.addRealRun(arrive);
RealRun leave = this.handleTrainLeave(data, strategy, trainPassenger, tripPlan, nextStationPlan, offsetTime);
data.addRealRun(leave);
trainPreviousMap.put(groupNumber, leave);
if (leave.getTime().toLocalTime().isBefore(nextTime)) {
nextTime = leave.getTime().toLocalTime();
}
}
}
}
}
private RealRun handleTrainLeave(StrategyCalculateData data, ParkTimeStrategy strategy, TrainPassenger trainPassenger,
TripPlan tripPlan, StationPlan stationPlan, int offsetTime) {
Stand stand = strategy.getStand();
int parkTime = stationPlan.getParkTime();
LocalTime arriveTime = stationPlan.getArriveTime();
LocalTime leaveTime = stationPlan.getLeaveTime();
if (Objects.equals(stationPlan.getSection(), stand.getSection())) {
parkTime = strategy.getTime();
leaveTime = arriveTime.plusSeconds(parkTime);
strategy.addTarget1(parkTime - stationPlan.getParkTime());
}
// 列车到站乘客上车更新列车上人数
StandPassenger standPassenger = data.getStandPassengerByStand(stationPlan.getSection().getStandList().get(0));
int wait = standPassenger.getWait(); // 站台等待乘客数
float predict = (parkTime - Config.INVALID_BOARD_TIME) * Config.PASSENGER_BOARD_SPEED; // 根据停站预测的可上车人数
int remain = Config.TRAIN_CAPACITY - trainPassenger.getNum(); // 列车上剩余可载人数
float min = Math.min(Math.min(wait, predict), remain); // 实际上车人数
standPassenger.minus(min);
trainPassenger.plus(min);
// 生成预测实际运行图
RealRun leave = this.buildRealRun(trainPassenger.getGroupNumber(), tripPlan, stationPlan, false, leaveTime, offsetTime, data.getSystemTime());
data.addRealRun(leave);
return leave;
}
}

View File

@ -1,10 +1,33 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
import club.joylink.rtss.simulation.cbtc.data.plan.StationPlan;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.Strategy;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StrategyCalculateData;
public interface StrategyService {
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
Strategy calculate(StrategyCalculateData data);
public interface StrategyService<T extends Strategy> {
List<T> generateStrategy(StrategyCalculateData data);
void calculate(StrategyCalculateData data, T strategy);
default RealRun buildRealRun(String groupNumber, TripPlan tripPlan,
StationPlan nextStationPlan, boolean arrive, LocalTime time, int offsetTime,
LocalDateTime systemTime) {
return RealRun.builder()
.groupNumber(groupNumber)
.serviceNumber(tripPlan.getServiceNumber())
.tripNumber(tripPlan.getTripNumber())
.right(tripPlan.isRight())
.stationCode(nextStationPlan.getStation().getCode())
.sectionCode(nextStationPlan.getSection().getCode())
.arrive(arrive)
.time(time.plusSeconds(offsetTime).atDate(systemTime.toLocalDate()))
.build();
}
}

View File

@ -1,11 +1,22 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import lombok.Getter;
@Getter
public class ParkTimeStrategy extends Strategy {
/** 站台code */
String standCode;
/**
* 站台
*/
Stand stand;
/** 停站时间 */
Integer time;
public ParkTimeStrategy(Stand stand, int parkTime) {
this.stand = stand;
this.time = parkTime;
}
@Override
public String buildDescription() {
this.description = "";

View File

@ -35,4 +35,8 @@ public class StandPassenger {
obj.wait = this.wait;
return obj;
}
public void minus(float n) {
this.wait -= n;
}
}

View File

@ -1,15 +1,34 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data;
import lombok.Getter;
@Getter
public abstract class Strategy {
String description;
/** 指标1时刻表偏差 */
Float target1;
int target1;
/** 指标2乘客等待时间 */
Float target2;
int target2;
/** 综合指标对指标12加权求和 */
Float coTarget;
int coTarget;
public abstract String buildDescription();
public void setTarget1(int target1) {
this.target1 = target1;
}
public void setTarget2(int target2) {
this.target2 = target2;
}
public void setCoTarget(int target) {
this.coTarget = target;
}
public void addTarget1(int i) {
this.target1 += i;
}
}

View File

@ -1,27 +1,31 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data;
import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.simulation.cbtc.data.plan.RealRun;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.passenger.data.StandPassengerFlow;
import club.joylink.rtss.simulation.cbtc.passenger.data.TrainPassengerFlow;
import lombok.Getter;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Getter
public class StrategyCalculateData {
LocalDateTime systemTime;
/**
* key-服务号
*/
Map<String, List<TripPlan>> planMap;
Map<String, List<TripPlan>> planMap = new ConcurrentHashMap<>();
/**
* key-服务车次
* key-列车车组
*/
Map<String, List<RealRun>> runMap;
Map<String, List<RealRun>> runMap = new ConcurrentHashMap<>();
Map<String, StandPassenger> standPassengerMap;
Map<String, StandPassenger> standPassengerMap = new ConcurrentHashMap<>();
List<TrainPassenger> trainPassengerList;
@ -29,28 +33,26 @@ public class StrategyCalculateData {
}
public StrategyCalculateData(Map<String, List<TripPlan>> serviceTripsMap,
public StrategyCalculateData(LocalDateTime systemTime,
Map<String, List<TripPlan>> serviceTripsMap,
List<RealRun> realRunRecordList,
List<StandPassengerFlow> allStandPassengerFlow,
List<TrainPassengerFlow> allTrainPassengerFlow) {
this.planMap = new HashMap<>(serviceTripsMap);
Map<String, List<RealRun>> realRunMap = new HashMap<>();
this.systemTime = systemTime;
this.planMap.putAll(serviceTripsMap);
for (RealRun realRun : realRunRecordList) {
String stNumber = realRun.getSTNumber();
List<RealRun> list = realRunMap.get(stNumber);
String groupNumber = realRun.getGroupNumber();
List<RealRun> list = this.runMap.get(groupNumber);
if (list == null) {
list = new ArrayList<>();
realRunMap.put(stNumber, list);
this.runMap.put(groupNumber, list);
}
list.add(realRun);
}
this.runMap = realRunMap;
Map<String, StandPassenger> spMap = new HashMap<>();
for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) {
StandPassenger standPassenger = new StandPassenger(standPassengerFlow);
spMap.put(standPassenger.getStand().getCode(), standPassenger);
this.standPassengerMap.put(standPassenger.getStand().getCode(), standPassenger);
}
this.standPassengerMap = spMap;
List<TrainPassenger> tpList = new ArrayList<>();
for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlow) {
TrainPassenger trainPassenger = new TrainPassenger(trainPassengerFlow);
@ -76,4 +78,50 @@ public class StrategyCalculateData {
return obj;
}
public List<StandPassenger> getAllStandPassengerList() {
return new ArrayList<>(this.standPassengerMap.values());
}
public TripPlan queryTripPlan(String serviceNumber, String tripNumber) {
List<TripPlan> tripPlanList = this.planMap.get(serviceNumber);
for (TripPlan tripPlan : tripPlanList) {
if (Objects.equals(tripPlan.getTripNumber(), tripNumber)) {
return tripPlan;
}
}
return null;
}
public RealRun queryPreviousRealRunData(String groupNumber) {
List<RealRun> realRuns = this.runMap.get(groupNumber);
if (!CollectionUtils.isEmpty(realRuns)) {
realRuns.sort(Comparator.comparing(RealRun::getTime));
return realRuns.get(realRuns.size() - 1);
}
return null;
}
public void addRealRun(RealRun realRun) {
List<RealRun> realRuns = this.runMap.get(realRun.getGroupNumber());
if (realRuns == null) {
realRuns = new ArrayList<>();
this.runMap.put(realRun.getGroupNumber(), realRuns);
}
realRuns.add(realRun);
}
public TripPlan queryNextTripPlan(TripPlan tripPlan) {
List<TripPlan> planList = this.planMap.get(tripPlan.getServiceNumber());
for (int i = 0; i < planList.size() - 1; i++) {
TripPlan plan = planList.get(i);
if (Objects.equals(plan, tripPlan)) {
return planList.get(i + 1);
}
}
return null;
}
public StandPassenger getStandPassengerByStand(Stand stand) {
return this.standPassengerMap.get(stand.getCode());
}
}

View File

@ -13,7 +13,7 @@ public class TrainPassenger {
String tripNumber;
/** 列车上人数 */
int remain;
int num;
public TrainPassenger() {
}
@ -22,7 +22,7 @@ public class TrainPassenger {
this.groupNumber = tpf.getTrain().getGroupNumber();
this.serviceNumber = tpf.getTrain().getServiceNumber();
this.tripNumber = tpf.getTrain().getTripNumber();
this.remain = tpf.getPassengerQuantity();
this.num = tpf.getPassengerQuantity();
}
public TrainPassenger clone() {
@ -30,7 +30,18 @@ public class TrainPassenger {
obj.groupNumber = this.groupNumber;
obj.serviceNumber = this.serviceNumber;
obj.tripNumber = this.tripNumber;
obj.remain = this.remain;
obj.num = this.num;
return obj;
}
public String getSTNumber() {
if (this.serviceNumber == null && this.tripNumber == null) {
return null;
}
return String.format("%s%s", this.serviceNumber, this.tripNumber == null ? "" : this.tripNumber);
}
public void plus(float n) {
this.num += n;
}
}