diff --git a/src/main/java/club/joylink/rtss/constants/Project.java b/src/main/java/club/joylink/rtss/constants/Project.java index 64758a342..a03cbda4b 100644 --- a/src/main/java/club/joylink/rtss/constants/Project.java +++ b/src/main/java/club/joylink/rtss/constants/Project.java @@ -26,6 +26,8 @@ public enum Project { DRTS, /** 北京交通大学项目(客流量科研) */ BJD, + /** 成都工业职业技术学院 */ + CGY, ; public static boolean isDefault(Project project) { diff --git a/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java b/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java index fd42e7c8e..2fd400479 100644 --- a/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java +++ b/src/main/java/club/joylink/rtss/services/runplan/RunPlanRoutingService.java @@ -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.Section; 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.vo.client.PageVO; import club.joylink.rtss.vo.client.map.MapVO; @@ -144,6 +145,18 @@ public class RunPlanRoutingService implements IRunPlanRoutingService { if (!planRunlevelService.isExisted(l)) { Section startSection = (Section) deviceMap.get(l.getStartSectionCode()); 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()); l.setDistance(distance); l.generateDefaultRunLevel(); diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java index 6aa2251fd..febeb1d8c 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/GeneratorNew.java @@ -18,6 +18,7 @@ import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -155,15 +156,32 @@ public interface GeneratorNew { // 添加步骤 List steps = new ArrayList<>(stepList.size()); stepList.forEach(operateStepVO -> { + + TrainingStepVO stepVO = new TrainingStepVO(operateStepVO); // if(StringUtils.hasText(stepVO.getCode()) && MapElement.DeviceType.ROUTE.equals(mapDevice.getDeviceType())) { // stepVO.setCode(((Route)mapDevice).getStart().getCode()); // } if (containPlaceholder(stepVO.getTip())) { - stepVO.setTip(replacePlaceholder(stepVO.getTip(), placeholderVOMap, mapDevice, simulation.getBuildParams().getMap())); + 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())); + } } if (containPlaceholder(stepVO.getVal())) { - stepVO.setVal(replacePlaceholder(stepVO.getVal(), placeholderVOMap, mapDevice, simulation.getBuildParams().getMap())); + stepVO.setVal(replacePlaceholder(stepVO.getVal(), placeholderVOMap,mapDevice, simulation.getBuildParams().getMap())); } steps.add(stepVO); }); diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SectionGeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SectionGeneratorNew.java index a1cf46eb7..98c007276 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SectionGeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SectionGeneratorNew.java @@ -76,8 +76,12 @@ public class SectionGeneratorNew implements GeneratorNew { case Section_Fault_Unlock: // 设置区段故障锁闭(这只是区故解的一种情况,后面再补其他情况) section.setFaultLock(true); + section.setRouteLock(true); if (section.isShowLogic()) { - section.getLogicList().forEach(s -> s.setFaultLock(true)); + section.getLogicList().forEach(s -> { + s.setFaultLock(true); + s.setRouteLock(true); + }); } break; case Section_Axis_Pre_Reset: diff --git a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SignalGeneratorNew.java b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SignalGeneratorNew.java index a9f110ed8..59f97b6ff 100644 --- a/src/main/java/club/joylink/rtss/services/training/generatornew/base/SignalGeneratorNew.java +++ b/src/main/java/club/joylink/rtss/services/training/generatornew/base/SignalGeneratorNew.java @@ -200,7 +200,7 @@ public class SignalGeneratorNew implements GeneratorNew { signal.setBlockade(true); break; } - case Signal_Open_Auto_Setting: { + case Signal_Open_Auto_Setting: { // 查询进路列表,背景为进路人工控 if (!CollectionUtils.isEmpty(routeList)) { if (routeLikeHa1 || operateDefinitionVO.onlyOperateSignal()) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Stand.java b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Stand.java index 139682d0e..ee4801d4e 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Stand.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/data/map/Stand.java @@ -276,6 +276,10 @@ public class Stand extends MayOutOfOrderDevice { return false; } + public String debugStr() { + return String.format("%s-%s-%s(%s)", this.station.getName(), + this.isRight()?"右行":"左行", this.getName(), this.getCode()); + } /** * 站台折返类型策略 diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/PassengerFlowSimulateService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/PassengerFlowSimulateService.java index e4d5d523b..ef8a4647f 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/PassengerFlowSimulateService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/PassengerFlowSimulateService.java @@ -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.SimulationRunAsPlanEvent; 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.vo.UserVO; import club.joylink.rtss.vo.client.SocketMessageVO; @@ -284,24 +284,32 @@ public class PassengerFlowSimulateService { //三维 List> sendDataList = new ArrayList<>(); PassengerFlowData passengerFlowData = passengerFlowSimulationData.getPassengerFlowData(); - String systemTimeStr = DateTimeUtil.format(systemTime.toLocalTime()); + // 当前时间 Map standTimePassengerFlowDataMap = passengerFlowData.queryTimeStandPFData(systemTime.toLocalTime()); + // 30s前 + Map preTimePassengerFlowDataMap = passengerFlowData.queryTimeStandPFData(systemTime.toLocalTime().minusSeconds(30)); + List allStandPassengerFlow = passengerFlowSimulationData.getAllStandPassengerFlow(); for (StandPassengerFlow standPassengerFlow : allStandPassengerFlow) { Map sendData = new HashMap<>(); Stand stand = standPassengerFlow.getStand(); 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) { // 列车拉走了站台上的人 - add = flowData.getNum(); + if (flowData.getNum() != 0 && preData.getNum() > 1000) { + add = 80; + } else { + add = flowData.getNum(); + } } + int total = standPassengerFlow.plus(add); sendData.put("standCode", stand.getCode()); - sendData.put("num", flowData.getNum()); + sendData.put("num", total); sendData.put("to", add); sendDataList.add(sendData); - standPassengerFlow.passengerEnter(add); - standPassengerFlow.reload(flowData.getNum()); } sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, sendDataList); } @@ -334,7 +342,7 @@ public class PassengerFlowSimulateService { } @Async("nsExecutor") - @Scheduled(fixedRate = 500) + @Scheduled(fixedRate = 1000) public void trainPassengerFlowSimulate() { passengerFlowSimulationDataMap.forEach((group, passengerFlowSimulationData) -> { Simulation simulation = this.groupSimulationCache.getSimulationByGroup(group); @@ -370,38 +378,34 @@ public class PassengerFlowSimulateService { Station station = standSection.getStation(); TripPlan tripPlan = repository.getTripPlan(trainInfo.getServiceNumber(), trainInfo.getTripNumber()); 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 sendData = new HashMap<>(); sendData.put("code", train.getGroupNumber()); - sendData.put("in", in); - if (Objects.isNull(trainPassengerFlow.getStation())) { - if (train.getTerminalStation().equals(station)) { - if (trainPassengerFlow.getPassengerQuantity() > tripStationPassengerFlowData.getDown()) { - log.warn("列车[{}]到达终点站,车上乘客人数[{}]多余下车人数[{}]", train.getGroupNumber(), - trainPassengerFlow.getPassengerQuantity(), tripStationPassengerFlowData.getDown()); - } - // 全部下车 - sendData.put("out", trainPassengerFlow.getPassengerQuantity()); - trainPassengerFlow.startOutboard(station, trainPassengerFlow.getPassengerQuantity()); + // 计算下车 + int down = 0; + if (!trainPassengerFlow.isOff()) { + if (Objects.equals(train.getTerminalStation(), station)) { + // 到达终点站 + down = trainPassengerFlow.getPassengerQuantity(); + } else if (Objects.nonNull(tripStationPassengerFlowData)) { + down = tripStationPassengerFlowData.getDown(); } else { - sendData.put("out", tripStationPassengerFlowData.getDown()); - trainPassengerFlow.startOutboard(station, tripStationPassengerFlowData.getDown()); + // 如果没有数据,默认下车5%的人 + down = (int) (trainPassengerFlow.getPassengerQuantity() * 0.05); } - } else { - sendData.put("out", 0); + trainPassengerFlow.minus(down); } - 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); SocketMessageVO message = SocketMessageFactory.build( @@ -411,9 +415,9 @@ public class PassengerFlowSimulateService { // 发送站台数据变更 Map sendStandData = new HashMap<>(); sendStandData.put("standCode", stand.getCode()); - sendStandData.put("num", standPassengerFlow.getPassengerQuantity() - in); + sendStandData.put("num", standWait - up); sendStandData.put("to", 0); - standPassengerFlow.passengerGetTrain(in); + standPassengerFlow.minus(up); sendStandPassengerToUser(simulation, systemTime, passengerFlowSimulationData, Collections.singletonList(sendStandData)); } }); diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/StandPassengerFlow.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/StandPassengerFlow.java index 24ed4ad83..1bdaece4a 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/StandPassengerFlow.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/StandPassengerFlow.java @@ -1,12 +1,8 @@ package club.joylink.rtss.simulation.cbtc.passenger.data; import club.joylink.rtss.simulation.cbtc.data.map.Stand; -import club.joylink.rtss.util.RandomGenerator; import lombok.Getter; -import java.time.LocalDateTime; -import java.time.LocalTime; - @Getter public class StandPassengerFlow { private int PassengerCapacity = 150; @@ -25,12 +21,17 @@ public class StandPassengerFlow { this.passengerQuantity = num; } - public void passengerEnter(int add) { + public synchronized int plus(int add) { this.passengerQuantity += add; + return this.passengerQuantity; } - public void passengerGetTrain(int num) { - this.passengerQuantity -= num; + public synchronized void minus(int num) { + if (this.passengerQuantity < num) { + this.passengerQuantity = 0; + } else { + this.passengerQuantity -= num; + } } public void reload(int num) { diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/TrainPassengerFlow.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/TrainPassengerFlow.java index ea7ae0173..fdd4cdd48 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/TrainPassengerFlow.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/data/TrainPassengerFlow.java @@ -1,6 +1,5 @@ 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 lombok.Getter; @@ -10,8 +9,8 @@ public class TrainPassengerFlow { private int passengerQuantity = 0; - /** 当前执行乘降的车站 */ - private Station station; + /** 乘客是否已经下车 */ + private boolean off; public TrainPassengerFlow(VirtualRealityTrain train) { this.train = train; @@ -21,27 +20,20 @@ public class TrainPassengerFlow { this.passengerQuantity = num; } - public void startBoarding(Station station, int up, int down, int remain) { - this.station = station; - this.passengerQuantity = remain; - } - - public void startOutboard(Station station, int num) { - this.station = station; - this.passengerQuantity -= num; - } - - public void startBoarding(Station station, int num) { - this.station = station; - this.passengerQuantity += num; - } - - public void startBoarding(Station station, TripStationPassengerFlowData tripStationPassengerFlowData) { - this.station = station; - this.passengerQuantity = tripStationPassengerFlowData.getRemain(); - } - public void endBoarding() { - this.station = null; + this.off = false; + } + + public void minus(int num) { + if (this.passengerQuantity < num) { + this.passengerQuantity = 0; + } else { + this.passengerQuantity -= num; + } + this.off = true; + } + + public void plus(int up) { + this.passengerQuantity += up; } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/Config.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/Config.java index ea78828a4..8ab4b1bfa 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/Config.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/Config.java @@ -9,8 +9,12 @@ 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 float PASSENGER_ON_SPEED = 12; + /** 站台无效的上车时间(开关门6s+下车4s+发车前确认5s) */ + 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; } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/LargePassengerFlowStrategyService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/LargePassengerFlowStrategyService.java index 54ff983d3..c1b3e6830 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/LargePassengerFlowStrategyService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/LargePassengerFlowStrategyService.java @@ -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.data.PassengerFlowSimulationData; 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.websocket.StompMessageService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; 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; +@Slf4j @Component public class LargePassengerFlowStrategyService { @Autowired private PassengerFlowSimulateService passengerFlowSimulateService; +// private ExecutorService executorService = Executors.newFixedThreadPool(4); + @Autowired private StompMessageService stompMessageService; - @Scheduled(fixedRate = 300*1000) + @Autowired + private ParkTimeStrategyServiceImpl parkTimeStrategyService; + + @Scheduled(fixedRate = 30*1000) public void checkLpf() { List pfSimulationList = this.passengerFlowSimulateService.getPassengerFlowSimulations(); if (CollectionUtils.isEmpty(pfSimulationList)) { @@ -42,18 +51,27 @@ public class LargePassengerFlowStrategyService { } } if (!lpfList.isEmpty()) { + log.info(String.format("[%s]出现大客流,开始生成策略计算", lpfList.get(0).getStand().debugStr())); // 发现大客流,计算策略 StrategyCalculateData strategyCalculateData = this.buildStrategyCalculateData(passengerFlowSimulationData); - + List 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) { Simulation simulation = this.passengerFlowSimulateService.getSimulationByGroup(passengerFlowSimulationData.getGroup()); + LocalDateTime systemTime = simulation.getSystemTime(); SimulationDataRepository repository = simulation.getRepository(); Map> serviceTripsMap = repository.getServiceTripsMap(); StrategyCalculateData strategyCalculateData = new StrategyCalculateData( + systemTime, serviceTripsMap, repository.getRealRunRecordList(), passengerFlowSimulationData.getAllStandPassengerFlow(), diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/ParkTimeStrategyServiceImpl.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/ParkTimeStrategyServiceImpl.java index 012e52ba2..e83f3ed17 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/ParkTimeStrategyServiceImpl.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/ParkTimeStrategyServiceImpl.java @@ -1,14 +1,186 @@ 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 { @Override - public Strategy calculate(StrategyCalculateData data) { - return null; + public List generateStrategy(StrategyCalculateData data) { + List list = new ArrayList<>(); + Stand stand = null; + // 暂时按一个站大客流处理 + List standPassengerList = data.getAllStandPassengerList(); + for (StandPassenger standPassenger : standPassengerList) { + if (standPassenger.isLpf()) { + stand = standPassenger.getStand(); + break; + } + } + if (stand == null) { + return null; + } + Map> planMap = data.getPlanMap(); + int planParkTime = 0; // 计划停站时间 + for (List planList : planMap.values()) { + for (TripPlan tripPlan : planList) { + List 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 trainPassengerList = data.getTrainPassengerList(); + Map 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 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; } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/StrategyService.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/StrategyService.java index 8f758f7b9..c23f9e265 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/StrategyService.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/StrategyService.java @@ -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 { + List 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(); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/ParkTimeStrategy.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/ParkTimeStrategy.java index 545b08cd2..cc178e7f4 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/ParkTimeStrategy.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/ParkTimeStrategy.java @@ -1,14 +1,25 @@ 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 = ""; - return null; + this.description = String.format("站台%s设置停站时间[%s]", stand.debugStr(), time); + return this.description; } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StandPassenger.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StandPassenger.java index ae084a058..d39aa9fcf 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StandPassenger.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StandPassenger.java @@ -35,4 +35,8 @@ public class StandPassenger { obj.wait = this.wait; return obj; } + + public void minus(float n) { + this.wait -= n; + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/Strategy.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/Strategy.java index 3918694f7..976b417d3 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/Strategy.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/Strategy.java @@ -1,15 +1,50 @@ package club.joylink.rtss.simulation.cbtc.passenger.strategy.data; +import lombok.Getter; + +@Getter public abstract class Strategy { String description; /** 指标1:时刻表偏差 */ - Float target1; + int target1; + /** + * 权重1 + */ + int w1 = 1; /** 指标2:乘客等待时间 */ - Float target2; + int target2; + /** + * 权重2 + */ + int w2 = 1; /** 综合指标:对指标1,2加权求和 */ - 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; + } + + 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); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StrategyCalculateData.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StrategyCalculateData.java index a6bc9189e..b4be85aef 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StrategyCalculateData.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/StrategyCalculateData.java @@ -1,27 +1,34 @@ 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 lombok.extern.slf4j.Slf4j; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -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; +@Slf4j +@Getter public class StrategyCalculateData { + LocalDateTime systemTime; /** * key-服务号 */ - Map> planMap; + Map> planMap = new ConcurrentHashMap<>(); /** - * key-服务车次号 + * key-列车车组号 */ - Map> runMap; + Map> runMap = new ConcurrentHashMap<>(); - Map standPassengerMap; + Map standPassengerMap = new ConcurrentHashMap<>(); List trainPassengerList; @@ -29,30 +36,31 @@ public class StrategyCalculateData { } - public StrategyCalculateData(Map> serviceTripsMap, + public StrategyCalculateData(LocalDateTime systemTime, + Map> serviceTripsMap, List realRunRecordList, List allStandPassengerFlow, List allTrainPassengerFlow) { - this.planMap = new HashMap<>(serviceTripsMap); - Map> realRunMap = new HashMap<>(); + this.systemTime = systemTime; + this.planMap.putAll(serviceTripsMap); for (RealRun realRun : realRunRecordList) { - String stNumber = realRun.getSTNumber(); - List list = realRunMap.get(stNumber); + String groupNumber = realRun.getGroupNumber(); + List 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 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 tpList = new ArrayList<>(); for (TrainPassengerFlow trainPassengerFlow : allTrainPassengerFlow) { + if (!StringUtils.hasText(trainPassengerFlow.getTrain().getServiceNumber())) { + continue; + } TrainPassenger trainPassenger = new TrainPassenger(trainPassengerFlow); tpList.add(trainPassenger); } @@ -61,8 +69,17 @@ public class StrategyCalculateData { public StrategyCalculateData clone() { StrategyCalculateData obj = new StrategyCalculateData(); - obj.planMap = new HashMap<>(this.planMap); - obj.runMap = new HashMap<>(this.runMap); + obj.systemTime = this.systemTime; + Map> copyPlanMap = new ConcurrentHashMap<>(); + this.planMap.forEach((code, list) -> { + copyPlanMap.put(code, new ArrayList<>(list)); + }); + obj.planMap = copyPlanMap; + Map> copyRunMap = new ConcurrentHashMap<>(); + this.runMap.forEach((code, list) -> { + copyRunMap.put(code, new ArrayList<>(list)); + }); + obj.runMap = copyRunMap; Map standPassengerMap = new HashMap<>(); this.standPassengerMap.forEach((code, standPassenger) -> { standPassengerMap.put(code, standPassenger.clone()); @@ -76,4 +93,54 @@ public class StrategyCalculateData { return obj; } + public List getAllStandPassengerList() { + return new ArrayList<>(this.standPassengerMap.values()); + } + + public TripPlan queryTripPlan(String serviceNumber, String tripNumber) { + List 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 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 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 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()); + } } diff --git a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/TrainPassenger.java b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/TrainPassenger.java index 24bb51080..c12911cdc 100644 --- a/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/TrainPassenger.java +++ b/src/main/java/club/joylink/rtss/simulation/cbtc/passenger/strategy/data/TrainPassenger.java @@ -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; + } }