| | |
| | | private static final double WAIT_ISSUED_RESERVE_SECONDS = 8.0d; |
| | | private static final double WAIT_PENDING_QUEUE_SECONDS = 5.0d; |
| | | private static final double WAIT_RUN_BLOCK_SECONDS = 30.0d; |
| | | private static final int DEADLOCK_PREFIX_LOOKAHEAD = 6; |
| | | |
| | | @Autowired |
| | | private BasStationService basStationService; |
| | |
| | | private StationTaskTraceRegistry stationTaskTraceRegistry; |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) { |
| | | return calcByStationId(startStationId, endStationId, null); |
| | | } |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId, Integer currentTaskNo) { |
| | | BasStation startStation = basStationService.getById(startStationId); |
| | | if (startStation == null) { |
| | | throw new CoolException("未找到该 起点 对应的站点数据"); |
| | |
| | | |
| | | startTime = System.currentTimeMillis(); |
| | | News.info("[WCS Debug] 站点路径权重开始分析,startStationId={},endStationId={}", startStationId, endStationId); |
| | | List<NavigateNode> list = findStationBestPathTwoStage(allList, resolvedPolicy); |
| | | List<NavigateNode> list = findStationBestPathTwoStage(allList, resolvedPolicy, currentTaskNo); |
| | | News.info("[WCS Debug] 站点路径权重分析完成,耗时:{}ms", System.currentTimeMillis() - startTime); |
| | | |
| | | //去重 |
| | |
| | | return new StationPathResolvedPolicy(); |
| | | } |
| | | |
| | | private List<NavigateNode> findStationBestPathTwoStage(List<List<NavigateNode>> allList, StationPathResolvedPolicy resolvedPolicy) { |
| | | private List<NavigateNode> findStationBestPathTwoStage(List<List<NavigateNode>> allList, |
| | | StationPathResolvedPolicy resolvedPolicy, |
| | | Integer currentTaskNo) { |
| | | if (allList == null || allList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | | } |
| | |
| | | |
| | | Map<Integer, StationProtocol> statusMap = loadStationStatusMap(); |
| | | Map<Integer, Double> stationLoopLoadMap = loadStationLoopLoadMap(); |
| | | StationTrafficSnapshot trafficSnapshot = loadStationTrafficSnapshot(statusMap); |
| | | StationTrafficSnapshot trafficSnapshot = loadStationTrafficSnapshot(statusMap, currentTaskNo); |
| | | Set<Integer> outStationIdSet = loadAllOutStationIdSet(); |
| | | List<PathCandidateMetrics> metricsList = new ArrayList<>(); |
| | | int skippedByOtherOutStation = 0; |
| | |
| | | metrics.congestionScore = calcCongestionScore(stationIdList, trafficSnapshot); |
| | | metrics.queueDepthScore = calcQueueDepthScore(stationIdList, trafficSnapshot); |
| | | metrics.estimatedWaitSeconds = calcEstimatedWaitSeconds(stationIdList, trafficSnapshot); |
| | | metrics.deadlockRiskScore = calcDeadlockRiskScore(stationIdList, trafficSnapshot); |
| | | metrics.runBlockCount = countRunBlockCount(stationIdList, statusMap); |
| | | metrics.loopPenalty = calcLoopPenalty(stationIdList, stationLoopLoadMap); |
| | | metrics.passOtherOutStationCount = countPassOtherOutStations(path, outStationIdSet); |
| | |
| | | safeDouble(profileConfig.getS2BusyWeight(), 2.0d) * congWeightFactor * metrics.congestionScore |
| | | + safeDouble(profileConfig.getS2QueueWeight(), 2.5d) * metrics.queueDepthScore |
| | | + safeDouble(profileConfig.getS2WaitWeight(), 1.5d) * (metrics.estimatedWaitSeconds / 60.0d) |
| | | + safeDouble(profileConfig.getS2DeadlockWeight(), 8.0d) * metrics.deadlockRiskScore |
| | | + safeDouble(profileConfig.getS2RunBlockWeight(), 10.0d) * metrics.runBlockCount |
| | | + safeDouble(profileConfig.getS2LoopLoadWeight(), 12.0d) * metrics.loopPenalty; |
| | | return metrics; |
| | |
| | | score += trafficSnapshot.estimatedWaitSecondsMap.getOrDefault(stationId, 0.0d); |
| | | } |
| | | return score; |
| | | } |
| | | |
| | | private double calcDeadlockRiskScore(List<Integer> stationIdList, StationTrafficSnapshot trafficSnapshot) { |
| | | if (trafficSnapshot == null || trafficSnapshot.traceRouteList.isEmpty() || stationIdList == null || stationIdList.size() <= 1) { |
| | | return 0.0d; |
| | | } |
| | | List<Integer> candidateFutureStations = distinctPositiveStationIds(stationIdList.subList(1, stationIdList.size())); |
| | | if (candidateFutureStations.isEmpty()) { |
| | | return 0.0d; |
| | | } |
| | | |
| | | double totalRisk = 0.0d; |
| | | for (TraceRouteSnapshot routeSnapshot : trafficSnapshot.traceRouteList) { |
| | | if (routeSnapshot == null) { |
| | | continue; |
| | | } |
| | | OverlapMetrics pendingMetrics = calcOrderedOverlapMetrics(candidateFutureStations, routeSnapshot.pendingStationIds); |
| | | OverlapMetrics issuedMetrics = calcOrderedOverlapMetrics(candidateFutureStations, routeSnapshot.issuedStationIds); |
| | | |
| | | totalRisk += pendingMetrics.sequentialRisk * 0.9d; |
| | | totalRisk += issuedMetrics.sequentialRisk * 1.2d; |
| | | totalRisk += pendingMetrics.sharedCount * 0.12d; |
| | | totalRisk += issuedMetrics.sharedCount * 0.18d; |
| | | |
| | | int currentHitIndex = findFirstOverlapIndex(candidateFutureStations, routeSnapshot.currentStationId); |
| | | if (currentHitIndex >= 0) { |
| | | totalRisk += prefixRiskFactor(currentHitIndex) * 1.5d; |
| | | } |
| | | } |
| | | return totalRisk; |
| | | } |
| | | |
| | | private int countRunBlockCount(List<Integer> stationIdList, Map<Integer, StationProtocol> statusMap) { |
| | |
| | | return stationLoopLoadMap; |
| | | } |
| | | |
| | | private StationTrafficSnapshot loadStationTrafficSnapshot(Map<Integer, StationProtocol> statusMap) { |
| | | private StationTrafficSnapshot loadStationTrafficSnapshot(Map<Integer, StationProtocol> statusMap, Integer currentTaskNo) { |
| | | StationTrafficSnapshot snapshot = new StationTrafficSnapshot(); |
| | | Map<Integer, Integer> busyMap = new HashMap<>(); |
| | | Map<Integer, Integer> issuedReserveMap = new HashMap<>(); |
| | |
| | | } |
| | | } |
| | | |
| | | for (StationTaskTraceVo traceVo : loadActiveTraceList()) { |
| | | for (StationTaskTraceVo traceVo : loadActiveTraceList(currentTaskNo)) { |
| | | if (traceVo == null) { |
| | | continue; |
| | | } |
| | | List<Integer> pendingStationIds = distinctPositiveStationIds(traceVo.getPendingStationIds()); |
| | | List<Integer> issuedStationIds = distinctPositiveStationIds(traceVo.getLatestIssuedSegmentPath()); |
| | | TraceRouteSnapshot routeSnapshot = new TraceRouteSnapshot(); |
| | | routeSnapshot.taskNo = traceVo.getTaskNo(); |
| | | routeSnapshot.currentStationId = traceVo.getCurrentStationId(); |
| | | routeSnapshot.pendingStationIds = pendingStationIds; |
| | | routeSnapshot.issuedStationIds = issuedStationIds; |
| | | snapshot.traceRouteList.add(routeSnapshot); |
| | | Set<Integer> pendingSet = new HashSet<>(pendingStationIds); |
| | | for (Integer stationId : issuedStationIds) { |
| | | if (stationId == null || !pendingSet.contains(stationId)) { |
| | |
| | | return snapshot; |
| | | } |
| | | |
| | | private List<StationTaskTraceVo> loadActiveTraceList() { |
| | | private List<StationTaskTraceVo> loadActiveTraceList(Integer currentTaskNo) { |
| | | if (stationTaskTraceRegistry == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | |
| | | List<StationTaskTraceVo> result = new ArrayList<>(); |
| | | for (StationTaskTraceVo traceVo : traceList) { |
| | | if (!isPlanningActiveTrace(traceVo)) { |
| | | continue; |
| | | } |
| | | if (currentTaskNo != null && currentTaskNo.equals(traceVo.getTaskNo())) { |
| | | continue; |
| | | } |
| | | result.add(traceVo); |
| | |
| | | target.put(stationId, target.getOrDefault(stationId, 0) + delta); |
| | | } |
| | | |
| | | private OverlapMetrics calcOrderedOverlapMetrics(List<Integer> candidateStations, List<Integer> routeStations) { |
| | | OverlapMetrics metrics = new OverlapMetrics(); |
| | | if (candidateStations == null || candidateStations.isEmpty() || routeStations == null || routeStations.isEmpty()) { |
| | | return metrics; |
| | | } |
| | | |
| | | Map<Integer, Integer> routeIndexMap = new HashMap<>(); |
| | | for (int i = 0; i < routeStations.size(); i++) { |
| | | Integer stationId = routeStations.get(i); |
| | | if (stationId != null && !routeIndexMap.containsKey(stationId)) { |
| | | routeIndexMap.put(stationId, i); |
| | | } |
| | | } |
| | | if (routeIndexMap.isEmpty()) { |
| | | return metrics; |
| | | } |
| | | |
| | | for (int i = 0; i < candidateStations.size(); i++) { |
| | | Integer stationId = candidateStations.get(i); |
| | | if (stationId != null && routeIndexMap.containsKey(stationId)) { |
| | | metrics.sharedCount++; |
| | | } |
| | | } |
| | | |
| | | for (int candidateStart = 0; candidateStart < candidateStations.size(); candidateStart++) { |
| | | Integer firstStation = candidateStations.get(candidateStart); |
| | | Integer routeStart = routeIndexMap.get(firstStation); |
| | | if (routeStart == null) { |
| | | continue; |
| | | } |
| | | |
| | | int length = 1; |
| | | int prevRouteIndex = routeStart; |
| | | for (int j = candidateStart + 1; j < candidateStations.size(); j++) { |
| | | Integer nextRouteIndex = routeIndexMap.get(candidateStations.get(j)); |
| | | if (nextRouteIndex == null || nextRouteIndex.intValue() != prevRouteIndex + 1) { |
| | | break; |
| | | } |
| | | length++; |
| | | prevRouteIndex = nextRouteIndex; |
| | | } |
| | | |
| | | double risk = length * prefixRiskFactor(candidateStart); |
| | | if (risk > metrics.sequentialRisk) { |
| | | metrics.sequentialRisk = risk; |
| | | } |
| | | } |
| | | return metrics; |
| | | } |
| | | |
| | | private int findFirstOverlapIndex(List<Integer> stationIdList, Integer targetStationId) { |
| | | if (stationIdList == null || stationIdList.isEmpty() || targetStationId == null) { |
| | | return -1; |
| | | } |
| | | for (int i = 0; i < stationIdList.size(); i++) { |
| | | Integer stationId = stationIdList.get(i); |
| | | if (targetStationId.equals(stationId)) { |
| | | return i; |
| | | } |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | private double prefixRiskFactor(int candidateIndex) { |
| | | if (candidateIndex < 0) { |
| | | return 0.0d; |
| | | } |
| | | if (candidateIndex >= DEADLOCK_PREFIX_LOOKAHEAD) { |
| | | return 0.15d; |
| | | } |
| | | return (double) (DEADLOCK_PREFIX_LOOKAHEAD - candidateIndex) / (double) DEADLOCK_PREFIX_LOOKAHEAD; |
| | | } |
| | | |
| | | private int compareDouble(double left, double right, int thenLeft1, int thenRight1, int thenLeft2, int thenRight2) { |
| | | int result = Double.compare(left, right); |
| | | if (result != 0) { |
| | |
| | | private double congestionScore; |
| | | private double queueDepthScore; |
| | | private double estimatedWaitSeconds; |
| | | private double deadlockRiskScore; |
| | | private int runBlockCount; |
| | | private int softDeviationCount; |
| | | private double loopPenalty; |
| | |
| | | private final Map<Integer, Double> congestionScoreMap = new HashMap<>(); |
| | | private final Map<Integer, Integer> queueDepthMap = new HashMap<>(); |
| | | private final Map<Integer, Double> estimatedWaitSecondsMap = new HashMap<>(); |
| | | private final List<TraceRouteSnapshot> traceRouteList = new ArrayList<>(); |
| | | } |
| | | |
| | | private static class TraceRouteSnapshot { |
| | | private Integer taskNo; |
| | | private Integer currentStationId; |
| | | private List<Integer> pendingStationIds = Collections.emptyList(); |
| | | private List<Integer> issuedStationIds = Collections.emptyList(); |
| | | } |
| | | |
| | | private static class OverlapMetrics { |
| | | private int sharedCount; |
| | | private double sequentialRisk; |
| | | } |
| | | |
| | | private static class PathGlobalPolicy { |