Merge remote-tracking branch 'origin/test' into test

This commit is contained in:
joylink_zhangsai 2021-01-26 18:41:56 +08:00
commit 2ddedd3134
18 changed files with 495 additions and 112 deletions

View File

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

View File

@ -12,6 +12,7 @@ import club.joylink.rtss.simulation.cbtc.data.CalculateService;
import club.joylink.rtss.simulation.cbtc.data.map.MapElement; import club.joylink.rtss.simulation.cbtc.data.map.MapElement;
import club.joylink.rtss.simulation.cbtc.data.map.Section; import club.joylink.rtss.simulation.cbtc.data.map.Section;
import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition; import club.joylink.rtss.simulation.cbtc.data.support.SectionPosition;
import club.joylink.rtss.simulation.cbtc.exception.SimulationException;
import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.client.PageVO; import club.joylink.rtss.vo.client.PageVO;
import club.joylink.rtss.vo.client.map.MapVO; import club.joylink.rtss.vo.client.map.MapVO;
@ -144,6 +145,18 @@ public class RunPlanRoutingService implements IRunPlanRoutingService {
if (!planRunlevelService.isExisted(l)) { if (!planRunlevelService.isExisted(l)) {
Section startSection = (Section) deviceMap.get(l.getStartSectionCode()); Section startSection = (Section) deviceMap.get(l.getStartSectionCode());
Section endSection = (Section) deviceMap.get(l.getEndSectionCode()); Section endSection = (Section) deviceMap.get(l.getEndSectionCode());
if((startSection.isStandTrack() && endSection.isTransferTrack()) || (endSection.isStandTrack() && startSection.isTransferTrack())){
Float distance;
try{
distance = CalculateService.calculateDistance(startSection, endSection, l.getRight());
}catch (SimulationException e){
distance = CalculateService.calculateDistance(startSection, endSection, !l.getRight());
}
l.setDistance(distance);
l.generateDefaultRunLevel();
planRunlevelService.createUserRunlevel(l);
return;
}
Float distance = CalculateService.calculateDistance(startSection, endSection, l.getRight()); Float distance = CalculateService.calculateDistance(startSection, endSection, l.getRight());
l.setDistance(distance); l.setDistance(distance);
l.generateDefaultRunLevel(); l.generateDefaultRunLevel();

View File

@ -18,6 +18,7 @@ import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -155,13 +156,30 @@ public interface GeneratorNew {
// 添加步骤 // 添加步骤
List<TrainingStepVO> steps = new ArrayList<>(stepList.size()); List<TrainingStepVO> steps = new ArrayList<>(stepList.size());
stepList.forEach(operateStepVO -> { stepList.forEach(operateStepVO -> {
TrainingStepVO stepVO = new TrainingStepVO(operateStepVO); TrainingStepVO stepVO = new TrainingStepVO(operateStepVO);
// if(StringUtils.hasText(stepVO.getCode()) && MapElement.DeviceType.ROUTE.equals(mapDevice.getDeviceType())) { // if(StringUtils.hasText(stepVO.getCode()) && MapElement.DeviceType.ROUTE.equals(mapDevice.getDeviceType())) {
// stepVO.setCode(((Route)mapDevice).getStart().getCode()); // stepVO.setCode(((Route)mapDevice).getStart().getCode());
// } // }
if (containPlaceholder(stepVO.getTip())) { if (containPlaceholder(stepVO.getTip())) {
if (StringUtils.hasText(operateStepVO.getCodeType())) {
TrainingConsts.CodeType codeType = TrainingConsts.CodeType.valueOf(operateStepVO.getCodeType());
MapElement operSignal = null;
if (Objects.nonNull(codeType) && MapElement.DeviceType.ROUTE.equals(mapDevice.getDeviceType())) {
if (codeType == TrainingConsts.CodeType.START_SIGNAL) {
operSignal = ((Route) mapDevice).getStart();
} else if (codeType == TrainingConsts.CodeType.END_SIGNAL) {
operSignal = ((Route) mapDevice).getDestination();
} else if (codeType == TrainingConsts.CodeType.SIGNAL) {
operSignal = ((Route) mapDevice).getStart();
}
}
stepVO.setTip(replacePlaceholder(stepVO.getTip(), placeholderVOMap, Objects.isNull(operSignal) ? mapDevice : operSignal, simulation.getBuildParams().getMap()));
} else {
stepVO.setTip(replacePlaceholder(stepVO.getTip(), placeholderVOMap, mapDevice, simulation.getBuildParams().getMap())); stepVO.setTip(replacePlaceholder(stepVO.getTip(), placeholderVOMap, mapDevice, simulation.getBuildParams().getMap()));
} }
}
if (containPlaceholder(stepVO.getVal())) { if (containPlaceholder(stepVO.getVal())) {
stepVO.setVal(replacePlaceholder(stepVO.getVal(), placeholderVOMap,mapDevice, simulation.getBuildParams().getMap())); stepVO.setVal(replacePlaceholder(stepVO.getVal(), placeholderVOMap,mapDevice, simulation.getBuildParams().getMap()));
} }

View File

@ -76,8 +76,12 @@ public class SectionGeneratorNew implements GeneratorNew {
case Section_Fault_Unlock: case Section_Fault_Unlock:
// 设置区段故障锁闭这只是区故解的一种情况后面再补其他情况 // 设置区段故障锁闭这只是区故解的一种情况后面再补其他情况
section.setFaultLock(true); section.setFaultLock(true);
section.setRouteLock(true);
if (section.isShowLogic()) { if (section.isShowLogic()) {
section.getLogicList().forEach(s -> s.setFaultLock(true)); section.getLogicList().forEach(s -> {
s.setFaultLock(true);
s.setRouteLock(true);
});
} }
break; break;
case Section_Axis_Pre_Reset: case Section_Axis_Pre_Reset:

View File

@ -276,6 +276,10 @@ public class Stand extends MayOutOfOrderDevice {
return false; return false;
} }
public String debugStr() {
return String.format("%s-%s-%s(%s)", this.station.getName(),
this.isRight()?"右行":"左行", this.getName(), this.getCode());
}
/** /**
* 站台折返类型策略 * 站台折返类型策略

View File

@ -17,7 +17,7 @@ import club.joylink.rtss.simulation.cbtc.event.SimulationDestroyEvent;
import club.joylink.rtss.simulation.cbtc.event.SimulationResetEvent; import club.joylink.rtss.simulation.cbtc.event.SimulationResetEvent;
import club.joylink.rtss.simulation.cbtc.event.SimulationRunAsPlanEvent; import club.joylink.rtss.simulation.cbtc.event.SimulationRunAsPlanEvent;
import club.joylink.rtss.simulation.cbtc.passenger.data.*; import club.joylink.rtss.simulation.cbtc.passenger.data.*;
import club.joylink.rtss.util.DateTimeUtil; import club.joylink.rtss.simulation.cbtc.passenger.strategy.Config;
import club.joylink.rtss.util.JsonUtils; import club.joylink.rtss.util.JsonUtils;
import club.joylink.rtss.vo.UserVO; import club.joylink.rtss.vo.UserVO;
import club.joylink.rtss.vo.client.SocketMessageVO; import club.joylink.rtss.vo.client.SocketMessageVO;
@ -284,24 +284,32 @@ public class PassengerFlowSimulateService {
//三维 //三维
List<Map<String, Object>> sendDataList = new ArrayList<>(); List<Map<String, Object>> sendDataList = new ArrayList<>();
PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData(); PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData();
String systemTimeStr = DateTimeUtil.format(systemTime.toLocalTime()); // 当前时间
Map<String, StandTimePassengerFlowData> standTimePassengerFlowDataMap = passengerFlowData.queryTimeStandPFData(systemTime.toLocalTime()); Map<String, StandTimePassengerFlowData> standTimePassengerFlowDataMap = passengerFlowData.queryTimeStandPFData(systemTime.toLocalTime());
// 30s前
Map<String, StandTimePassengerFlowData> preTimePassengerFlowDataMap = passengerFlowData.queryTimeStandPFData(systemTime.toLocalTime().minusSeconds(30));
List<StandPassengerFlow> allStandPassengerFlow = passengerFlowSimulationData.getAllStandPassengerFlow(); List<StandPassengerFlow> allStandPassengerFlow = passengerFlowSimulationData.getAllStandPassengerFlow();
for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) { for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) {
Map<String, Object> sendData = new HashMap<>(); Map<String, Object> sendData = new HashMap<>();
Stand stand = standPassengerFlow.getStand(); Stand stand = standPassengerFlow.getStand();
StandTimePassengerFlowData flowData = standTimePassengerFlowDataMap.get(stand.getCode()); StandTimePassengerFlowData flowData = standTimePassengerFlowDataMap.get(stand.getCode());
int add = flowData.getNum() - standPassengerFlow.getLastLoad(); StandTimePassengerFlowData preData = preTimePassengerFlowDataMap.get(stand.getCode());
int add = flowData.getNum() - preData.getNum();
log.debug(String.format("站台[%s]增加乘客: %s", stand.debugStr(), add));
if (add < 0) { if (add < 0) {
// 列车拉走了站台上的人 // 列车拉走了站台上的人
if (flowData.getNum() != 0 && preData.getNum() > 1000) {
add = 80;
} else {
add = flowData.getNum(); add = flowData.getNum();
} }
}
int total = standPassengerFlow.plus(add);
sendData.put("standCode", stand.getCode()); sendData.put("standCode", stand.getCode());
sendData.put("num", flowData.getNum()); sendData.put("num", total);
sendData.put("to", add); sendData.put("to", add);
sendDataList.add(sendData); sendDataList.add(sendData);
standPassengerFlow.passengerEnter(add);
standPassengerFlow.reload(flowData.getNum());
} }
sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, sendDataList); sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, sendDataList);
} }
@ -334,7 +342,7 @@ public class PassengerFlowSimulateService {
} }
@Async("nsExecutor") @Async("nsExecutor")
@Scheduled(fixedRate = 500) @Scheduled(fixedRate = 1000)
public void trainPassengerFlowSimulate() { public void trainPassengerFlowSimulate() {
passengerFlowSimulationDataMap.forEach((group, passengerFlowSimulationData) -> { passengerFlowSimulationDataMap.forEach((group, passengerFlowSimulationData) -> {
Simulation simulation = this.groupSimulationCache.getSimulationByGroup(group); Simulation simulation = this.groupSimulationCache.getSimulationByGroup(group);
@ -370,38 +378,34 @@ public class PassengerFlowSimulateService {
Station station = standSection.getStation(); Station station = standSection.getStation();
TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber()); TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber());
TripStationPassengerFlowData tripStationPassengerFlowData = passengerFlowData.queryStationTripPassengerFlowData(station.getCode(), tripPlan.getStNumber()); TripStationPassengerFlowData tripStationPassengerFlowData = passengerFlowData.queryStationTripPassengerFlowData(station.getCode(), tripPlan.getStNumber());
if (Objects.isNull(tripStationPassengerFlowData)) {
log.debug(String.format("车站[%s]列车车次[%s]客流数据不存在,不更新", station.debugStr(), tripPlan.debugStr()));
continue;
}
Stand stand = station.getStandOf(train.isRight()).get(0);
StandPassengerFlow standPassengerFlow = passengerFlowSimulationData.getStandPassengerFlowMap().get(stand.getCode());
if (standPassengerFlow.getPassengerQuantity() == 0 && Objects.nonNull(trainPassengerFlow.getStation())) {
// 已下过车且车站没人等车
continue;
}
// 列车最大容量1500
int in = Math.min(1500 - trainPassengerFlow.getPassengerQuantity(), standPassengerFlow.getPassengerQuantity());
Map<String, Object> sendData = new HashMap<>(); Map<String, Object> sendData = new HashMap<>();
sendData.put("code", train.getGroupNumber()); sendData.put("code", train.getGroupNumber());
sendData.put("in", in); // 计算下车
if (Objects.isNull(trainPassengerFlow.getStation())) { int down = 0;
if (train.getTerminalStation().equals(station)) { if (!trainPassengerFlow.isOff()) {
if (trainPassengerFlow.getPassengerQuantity() > tripStationPassengerFlowData.getDown()) { if (Objects.equals(train.getTerminalStation(), station)) {
log.warn("列车[{}]到达终点站,车上乘客人数[{}]多余下车人数[{}]", train.getGroupNumber(), // 到达终点站
trainPassengerFlow.getPassengerQuantity(), tripStationPassengerFlowData.getDown()); down = trainPassengerFlow.getPassengerQuantity();
} } else if (Objects.nonNull(tripStationPassengerFlowData)) {
// 全部下车 down = tripStationPassengerFlowData.getDown();
sendData.put("out", trainPassengerFlow.getPassengerQuantity());
trainPassengerFlow.startOutboard(station, trainPassengerFlow.getPassengerQuantity());
} else { } else {
sendData.put("out", tripStationPassengerFlowData.getDown()); // 如果没有数据默认下车5%的人
trainPassengerFlow.startOutboard(station, tripStationPassengerFlowData.getDown()); down = (int) (trainPassengerFlow.getPassengerQuantity() * 0.05);
} }
} else { trainPassengerFlow.minus(down);
sendData.put("out", 0);
} }
trainPassengerFlow.startBoarding(station, in); sendData.put("out", down);
// 上车
int remain = Config.TRAIN_CAPACITY - trainPassengerFlow.getPassengerQuantity();
int up = Math.min(Config.PASSENGER_BOARD_SPEED, remain);
Stand stand = station.getStandOf(train.isRight()).get(0);
StandPassengerFlow standPassengerFlow = passengerFlowSimulationData.getStandPassengerFlowMap().get(stand.getCode());
int standWait = standPassengerFlow.getPassengerQuantity();
if (standWait < up) {
up = standWait;
}
trainPassengerFlow.plus(up);
sendData.put("in", up);
String json = JsonUtils.writeValueNullableFieldAsString(sendData); String json = JsonUtils.writeValueNullableFieldAsString(sendData);
SocketMessageVO<String> message = SocketMessageFactory.build( SocketMessageVO<String> message = SocketMessageFactory.build(
@ -411,9 +415,9 @@ public class PassengerFlowSimulateService {
// 发送站台数据变更 // 发送站台数据变更
Map<String, Object> sendStandData = new HashMap<>(); Map<String, Object> sendStandData = new HashMap<>();
sendStandData.put("standCode", stand.getCode()); sendStandData.put("standCode", stand.getCode());
sendStandData.put("num", standPassengerFlow.getPassengerQuantity() - in); sendStandData.put("num", standWait - up);
sendStandData.put("to", 0); sendStandData.put("to", 0);
standPassengerFlow.passengerGetTrain(in); standPassengerFlow.minus(up);
sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, Collections.singletonList(sendStandData)); sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, Collections.singletonList(sendStandData));
} }
}); });

View File

@ -1,12 +1,8 @@
package club.joylink.rtss.simulation.cbtc.passenger.data; package club.joylink.rtss.simulation.cbtc.passenger.data;
import club.joylink.rtss.simulation.cbtc.data.map.Stand; import club.joylink.rtss.simulation.cbtc.data.map.Stand;
import club.joylink.rtss.util.RandomGenerator;
import lombok.Getter; import lombok.Getter;
import java.time.LocalDateTime;
import java.time.LocalTime;
@Getter @Getter
public class StandPassengerFlow { public class StandPassengerFlow {
private int PassengerCapacity = 150; private int PassengerCapacity = 150;
@ -25,13 +21,18 @@ public class StandPassengerFlow {
this.passengerQuantity = num; this.passengerQuantity = num;
} }
public void passengerEnter(int add) { public synchronized int plus(int add) {
this.passengerQuantity += add; this.passengerQuantity += add;
return this.passengerQuantity;
} }
public void passengerGetTrain(int num) { public synchronized void minus(int num) {
if (this.passengerQuantity < num) {
this.passengerQuantity = 0;
} else {
this.passengerQuantity -= num; this.passengerQuantity -= num;
} }
}
public void reload(int num) { public void reload(int num) {
this.lastLoad = num; this.lastLoad = num;

View File

@ -1,6 +1,5 @@
package club.joylink.rtss.simulation.cbtc.passenger.data; package club.joylink.rtss.simulation.cbtc.passenger.data;
import club.joylink.rtss.simulation.cbtc.data.map.Station;
import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain; import club.joylink.rtss.simulation.cbtc.data.vr.VirtualRealityTrain;
import lombok.Getter; import lombok.Getter;
@ -10,8 +9,8 @@ public class TrainPassengerFlow {
private int passengerQuantity = 0; private int passengerQuantity = 0;
/** 当前执行乘降的车站 */ /** 乘客是否已经下车 */
private Station station; private boolean off;
public TrainPassengerFlow(VirtualRealityTrain train) { public TrainPassengerFlow(VirtualRealityTrain train) {
this.train = train; this.train = train;
@ -21,27 +20,20 @@ public class TrainPassengerFlow {
this.passengerQuantity = num; this.passengerQuantity = num;
} }
public void startBoarding(Station station, int up, int down, int remain) { public void endBoarding() {
this.station = station; this.off = false;
this.passengerQuantity = remain;
} }
public void startOutboard(Station station, int num) { public void minus(int num) {
this.station = station; if (this.passengerQuantity < num) {
this.passengerQuantity = 0;
} else {
this.passengerQuantity -= num; this.passengerQuantity -= num;
} }
this.off = true;
public void startBoarding(Station station, int num) {
this.station = station;
this.passengerQuantity += num;
} }
public void startBoarding(Station station, TripStationPassengerFlowData tripStationPassengerFlowData) { public void plus(int up) {
this.station = station; this.passengerQuantity += up;
this.passengerQuantity = tripStationPassengerFlowData.getRemain();
}
public void endBoarding() {
this.station = null;
} }
} }

View File

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

View File

@ -6,27 +6,36 @@ import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan;
import club.joylink.rtss.simulation.cbtc.passenger.PassengerFlowSimulateService; import club.joylink.rtss.simulation.cbtc.passenger.PassengerFlowSimulateService;
import club.joylink.rtss.simulation.cbtc.passenger.data.PassengerFlowSimulationData; import club.joylink.rtss.simulation.cbtc.passenger.data.PassengerFlowSimulationData;
import club.joylink.rtss.simulation.cbtc.passenger.data.StandPassengerFlow; import club.joylink.rtss.simulation.cbtc.passenger.data.StandPassengerFlow;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.ParkTimeStrategy;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StrategyCalculateData; import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StrategyCalculateData;
import club.joylink.rtss.websocket.StompMessageService; import club.joylink.rtss.websocket.StompMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j
@Component @Component
public class LargePassengerFlowStrategyService { public class LargePassengerFlowStrategyService {
@Autowired @Autowired
private PassengerFlowSimulateService passengerFlowSimulateService; private PassengerFlowSimulateService passengerFlowSimulateService;
// private ExecutorService executorService = Executors.newFixedThreadPool(4);
@Autowired @Autowired
private StompMessageService stompMessageService; private StompMessageService stompMessageService;
@Scheduled(fixedRate = 300*1000) @Autowired
private ParkTimeStrategyServiceImpl parkTimeStrategyService;
@Scheduled(fixedRate = 30*1000)
public void checkLpf() { public void checkLpf() {
List<PassengerFlowSimulationData> pfSimulationList = this.passengerFlowSimulateService.getPassengerFlowSimulations(); List<PassengerFlowSimulationData> pfSimulationList = this.passengerFlowSimulateService.getPassengerFlowSimulations();
if (CollectionUtils.isEmpty(pfSimulationList)) { if (CollectionUtils.isEmpty(pfSimulationList)) {
@ -42,18 +51,27 @@ public class LargePassengerFlowStrategyService {
} }
} }
if (!lpfList.isEmpty()) { if (!lpfList.isEmpty()) {
log.info(String.format("[%s]出现大客流,开始生成策略计算", lpfList.get(0).getStand().debugStr()));
// 发现大客流计算策略 // 发现大客流计算策略
StrategyCalculateData strategyCalculateData = this.buildStrategyCalculateData(passengerFlowSimulationData); StrategyCalculateData strategyCalculateData = this.buildStrategyCalculateData(passengerFlowSimulationData);
List<ParkTimeStrategy> parkTimeStrategies = this.parkTimeStrategyService.generateStrategy(strategyCalculateData);
for (ParkTimeStrategy parkTimeStrategy : parkTimeStrategies) {
this.parkTimeStrategyService.calculate(strategyCalculateData.clone(), parkTimeStrategy);
parkTimeStrategy.buildDescription();
log.info(String.format("停站时间策略[%s]计算指标为:%s", parkTimeStrategy.getDescription(),
parkTimeStrategy.targetDebugStr()));
}
} }
} }
} }
private StrategyCalculateData buildStrategyCalculateData(PassengerFlowSimulationData passengerFlowSimulationData) { private StrategyCalculateData buildStrategyCalculateData(PassengerFlowSimulationData passengerFlowSimulationData) {
Simulation simulation = this.passengerFlowSimulateService.getSimulationByGroup(passengerFlowSimulationData.getGroup()); Simulation simulation = this.passengerFlowSimulateService.getSimulationByGroup(passengerFlowSimulationData.getGroup());
LocalDateTime systemTime = simulation.getSystemTime();
SimulationDataRepository repository = simulation.getRepository(); SimulationDataRepository repository = simulation.getRepository();
Map<String, List<TripPlan>> serviceTripsMap = repository.getServiceTripsMap(); Map<String, List<TripPlan>> serviceTripsMap = repository.getServiceTripsMap();
StrategyCalculateData strategyCalculateData = new StrategyCalculateData( StrategyCalculateData strategyCalculateData = new StrategyCalculateData(
systemTime,
serviceTripsMap, serviceTripsMap,
repository.getRealRunRecordList(), repository.getRealRunRecordList(),
passengerFlowSimulationData.getAllStandPassengerFlow(), passengerFlowSimulationData.getAllStandPassengerFlow(),

View File

@ -1,14 +1,186 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy; 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.StrategyCalculateData;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.TrainPassenger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.LocalTime;
import java.util.*;
@Slf4j
@Component @Component
public class ParkTimeStrategyServiceImpl implements StrategyService { public class ParkTimeStrategyServiceImpl implements StrategyService<ParkTimeStrategy> {
@Override @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; 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) {
// 系统时间
LocalTime systemTime = data.getSystemTime().toLocalTime();// 系统当前时间
LocalTime endTime = systemTime.plusMinutes(Config.STRATEGY_CAL_TIME);// 预测计算终点
List<TrainPassenger> trainPassengerList = data.getTrainPassengerList();
Map<String, RealRun> trainPreviousMap = new HashMap<>(); // 列车上一个到站/发车数据
int i = 0;
while (systemTime.isBefore(endTime) && i<1000) { // 在计算时间内
++i;
if (i > 999) {
log.error("死循环--------------------------");
}
LocalTime nextTime = null;
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);
} 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 (nextTime == null || leave.getTime().toLocalTime().isBefore(nextTime)) {
nextTime = leave.getTime().toLocalTime();
}
}
}
BusinessExceptionAssertEnum.SYSTEM_EXCEPTION.assertNotNull(nextTime);
systemTime = nextTime;
}
strategy.setCoTarget(strategy.getTarget1()*strategy.getW1()+strategy.getTarget2()*strategy.getW2());
}
private RealRun handleTrainLeave(StrategyCalculateData data, ParkTimeStrategy strategy, TrainPassenger trainPassenger,
TripPlan tripPlan, StationPlan stationPlan, int offsetTime) {
Stand stand = strategy.getStand();
int parkTime = strategy.getTime();
LocalTime arriveTime = stationPlan.getArriveTime();
LocalTime leaveTime = stationPlan.getLeaveTime();
// 列车到站乘客上车更新列车上人数
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);
// 大客流站计算指标
if (Objects.equals(stationPlan.getSection(), stand.getSection())) {
// 时刻表偏差
parkTime = strategy.getTime();
leaveTime = arriveTime.plusSeconds(parkTime);
strategy.addTarget1(parkTime - stationPlan.getParkTime());
// 乘客等待时间(按人数统计不考虑时间)
strategy.addTarget2(standPassenger.getWait());
}
return leave;
}
} }

View File

@ -1,10 +1,33 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy; 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.Strategy;
import club.joylink.rtss.simulation.cbtc.passenger.strategy.data.StrategyCalculateData; 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,14 +1,25 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data; 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 { public class ParkTimeStrategy extends Strategy {
/** 站台code */ /**
String standCode; * 站台
*/
Stand stand;
/** 停站时间 */ /** 停站时间 */
Integer time; Integer time;
public ParkTimeStrategy(Stand stand, int parkTime) {
this.stand = stand;
this.time = parkTime;
}
@Override @Override
public String buildDescription() { public String buildDescription() {
this.description = ""; this.description = String.format("站台%s设置停站时间[%s]", stand.debugStr(), time);
return null; return this.description;
} }
} }

View File

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

View File

@ -1,15 +1,50 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data; package club.joylink.rtss.simulation.cbtc.passenger.strategy.data;
import lombok.Getter;
@Getter
public abstract class Strategy { public abstract class Strategy {
String description; String description;
/** 指标1时刻表偏差 */ /** 指标1时刻表偏差 */
Float target1; int target1;
/**
* 权重1
*/
int w1 = 1;
/** 指标2乘客等待时间 */ /** 指标2乘客等待时间 */
Float target2; int target2;
/**
* 权重2
*/
int w2 = 1;
/** 综合指标对指标12加权求和 */ /** 综合指标对指标12加权求和 */
Float coTarget; int coTarget;
public abstract String buildDescription(); 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;
}
public void addTarget2(int wait) {
this.target2 += wait;
}
public String targetDebugStr() {
return String.format("指标1-时刻表偏差为:[%s],指标2-等待乘客数为:[%s],综合指标为:[%s]",this.target1, this.target2, this.coTarget);
}
} }

View File

@ -1,27 +1,34 @@
package club.joylink.rtss.simulation.cbtc.passenger.strategy.data; 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.RealRun;
import club.joylink.rtss.simulation.cbtc.data.plan.TripPlan; 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.StandPassengerFlow;
import club.joylink.rtss.simulation.cbtc.passenger.data.TrainPassengerFlow; import club.joylink.rtss.simulation.cbtc.passenger.data.TrainPassengerFlow;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.ArrayList; import java.time.LocalDateTime;
import java.util.HashMap; import java.util.*;
import java.util.List; import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
@Slf4j
@Getter
public class StrategyCalculateData { public class StrategyCalculateData {
LocalDateTime systemTime;
/** /**
* key-服务号 * 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; List<TrainPassenger> trainPassengerList;
@ -29,30 +36,31 @@ public class StrategyCalculateData {
} }
public StrategyCalculateData(Map<String, List<TripPlan>> serviceTripsMap, public StrategyCalculateData(LocalDateTime systemTime,
Map<String, List<TripPlan>> serviceTripsMap,
List<RealRun> realRunRecordList, List<RealRun> realRunRecordList,
List<StandPassengerFlow> allStandPassengerFlow, List<StandPassengerFlow> allStandPassengerFlow,
List<TrainPassengerFlow> allTrainPassengerFlow) { List<TrainPassengerFlow> allTrainPassengerFlow) {
this.planMap = new HashMap<>(serviceTripsMap); this.systemTime = systemTime;
Map<String, List<RealRun>> realRunMap = new HashMap<>(); this.planMap.putAll(serviceTripsMap);
for (RealRun realRun : realRunRecordList) { for (RealRun realRun : realRunRecordList) {
String stNumber = realRun.getSTNumber(); String groupNumber = realRun.getGroupNumber();
List<RealRun> list = realRunMap.get(stNumber); List<RealRun> list = this.runMap.get(groupNumber);
if (list == null) { if (list == null) {
list = new ArrayList<>(); list = new ArrayList<>();
realRunMap.put(stNumber, list); this.runMap.put(groupNumber, list);
} }
list.add(realRun); list.add(realRun);
} }
this.runMap = realRunMap;
Map<String, StandPassenger> spMap = new HashMap<>();
for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) { for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) {
StandPassenger standPassenger = new StandPassenger(standPassengerFlow); 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<>(); List<TrainPassenger> tpList = new ArrayList<>();
for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlow) { for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlow) {
if (!StringUtils.hasText(trainPassengerFlow.getTrain().getServiceNumber())) {
continue;
}
TrainPassenger trainPassenger = new TrainPassenger(trainPassengerFlow); TrainPassenger trainPassenger = new TrainPassenger(trainPassengerFlow);
tpList.add(trainPassenger); tpList.add(trainPassenger);
} }
@ -61,8 +69,17 @@ public class StrategyCalculateData {
public StrategyCalculateData clone() { public StrategyCalculateData clone() {
StrategyCalculateData obj = new StrategyCalculateData(); StrategyCalculateData obj = new StrategyCalculateData();
obj.planMap = new HashMap<>(this.planMap); obj.systemTime = this.systemTime;
obj.runMap = new HashMap<>(this.runMap); Map<String, List<TripPlan>> copyPlanMap = new ConcurrentHashMap<>();
this.planMap.forEach((code, list) -> {
copyPlanMap.put(code, new ArrayList<>(list));
});
obj.planMap = copyPlanMap;
Map<String, List<RealRun>> copyRunMap = new ConcurrentHashMap<>();
this.runMap.forEach((code, list) -> {
copyRunMap.put(code, new ArrayList<>(list));
});
obj.runMap = copyRunMap;
Map<String, StandPassenger> standPassengerMap = new HashMap<>(); Map<String, StandPassenger> standPassengerMap = new HashMap<>();
this.standPassengerMap.forEach((code, standPassenger) -> { this.standPassengerMap.forEach((code, standPassenger) -> {
standPassengerMap.put(code, standPassenger.clone()); standPassengerMap.put(code, standPassenger.clone());
@ -76,4 +93,54 @@ public class StrategyCalculateData {
return obj; 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);
if (CollectionUtils.isEmpty(tripPlanList)) {
log.warn(String.format("服务号[%s]没有车次计划", serviceNumber));
return null;
}
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; String tripNumber;
/** 列车上人数 */ /** 列车上人数 */
int remain; int num;
public TrainPassenger() { public TrainPassenger() {
} }
@ -22,7 +22,7 @@ public class TrainPassenger {
this.groupNumber = tpf.getTrain().getGroupNumber(); this.groupNumber = tpf.getTrain().getGroupNumber();
this.serviceNumber = tpf.getTrain().getServiceNumber(); this.serviceNumber = tpf.getTrain().getServiceNumber();
this.tripNumber = tpf.getTrain().getTripNumber(); this.tripNumber = tpf.getTrain().getTripNumber();
this.remain = tpf.getPassengerQuantity(); this.num = tpf.getPassengerQuantity();
} }
public TrainPassenger clone() { public TrainPassenger clone() {
@ -30,7 +30,18 @@ public class TrainPassenger {
obj.groupNumber = this.groupNumber; obj.groupNumber = this.groupNumber;
obj.serviceNumber = this.serviceNumber; obj.serviceNumber = this.serviceNumber;
obj.tripNumber = this.tripNumber; obj.tripNumber = this.tripNumber;
obj.remain = this.remain; obj.num = this.num;
return obj; 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;
}
} }