| | |
| | | import com.zy.asrs.domain.path.StationPathProfileConfig; |
| | | import com.zy.asrs.domain.path.StationPathResolvedPolicy; |
| | | import com.zy.asrs.domain.path.StationPathRuleConfig; |
| | | import com.zy.asrs.domain.vo.StationTaskTraceVo; |
| | | import com.zy.asrs.domain.vo.StationCycleCapacityVo; |
| | | import com.zy.asrs.domain.vo.StationCycleLoopVo; |
| | | import com.zy.asrs.entity.BasDevp; |
| | |
| | | import com.zy.core.enums.SlaveType; |
| | | import com.zy.core.model.protocol.StationProtocol; |
| | | import com.zy.core.thread.StationThread; |
| | | import com.zy.core.trace.StationTaskTraceRegistry; |
| | | |
| | | @Component |
| | | public class NavigateUtils { |
| | | |
| | | private static final double CONGESTION_BUSY_BASE = 1.0d; |
| | | private static final double CONGESTION_ISSUED_RESERVE_BASE = 0.75d; |
| | | private static final double CONGESTION_PENDING_QUEUE_BASE = 0.45d; |
| | | private static final double CONGESTION_RUN_BLOCK_BASE = 1.5d; |
| | | private static final double WAIT_BUSY_SECONDS = 10.0d; |
| | | 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; |
| | | |
| | | @Autowired |
| | | private BasStationService basStationService; |
| | |
| | | private StationPathPolicyService stationPathPolicyService; |
| | | @Autowired |
| | | private StationCycleCapacityService stationCycleCapacityService; |
| | | @Autowired |
| | | private StationTaskTraceRegistry stationTaskTraceRegistry; |
| | | |
| | | public synchronized List<NavigateNode> calcByStationId(Integer startStationId, Integer endStationId) { |
| | | BasStation startStation = basStationService.getById(startStationId); |
| | |
| | | |
| | | Map<Integer, StationProtocol> statusMap = loadStationStatusMap(); |
| | | Map<Integer, Double> stationLoopLoadMap = loadStationLoopLoadMap(); |
| | | StationTrafficSnapshot trafficSnapshot = loadStationTrafficSnapshot(statusMap); |
| | | Set<Integer> outStationIdSet = loadAllOutStationIdSet(); |
| | | List<PathCandidateMetrics> metricsList = new ArrayList<>(); |
| | | int skippedByOtherOutStation = 0; |
| | |
| | | if (path == null || path.isEmpty()) { |
| | | continue; |
| | | } |
| | | PathCandidateMetrics metrics = buildCandidateMetrics(path, statusMap, stationLoopLoadMap, profileConfig, ruleConfig, globalPolicy, outStationIdSet); |
| | | PathCandidateMetrics metrics = buildCandidateMetrics(path, statusMap, stationLoopLoadMap, trafficSnapshot, profileConfig, ruleConfig, globalPolicy, outStationIdSet); |
| | | if (globalPolicy.forceSkipPassOtherOutStation && metrics.passOtherOutStationCount > 0) { |
| | | skippedByOtherOutStation++; |
| | | continue; |
| | |
| | | private PathCandidateMetrics buildCandidateMetrics(List<NavigateNode> path, |
| | | Map<Integer, StationProtocol> statusMap, |
| | | Map<Integer, Double> stationLoopLoadMap, |
| | | StationTrafficSnapshot trafficSnapshot, |
| | | StationPathProfileConfig profileConfig, |
| | | StationPathRuleConfig ruleConfig, |
| | | PathGlobalPolicy globalPolicy, |
| | |
| | | metrics.liftTransferCount = countLiftTransferCount(path); |
| | | |
| | | List<Integer> stationIdList = extractStationIdList(path); |
| | | metrics.busyStationCount = countBusyStationCount(stationIdList, statusMap); |
| | | metrics.congestionScore = calcCongestionScore(stationIdList, trafficSnapshot); |
| | | metrics.queueDepthScore = calcQueueDepthScore(stationIdList, trafficSnapshot); |
| | | metrics.estimatedWaitSeconds = calcEstimatedWaitSeconds(stationIdList, trafficSnapshot); |
| | | metrics.runBlockCount = countRunBlockCount(stationIdList, statusMap); |
| | | metrics.loopPenalty = calcLoopPenalty(stationIdList, stationLoopLoadMap); |
| | | metrics.passOtherOutStationCount = countPassOtherOutStations(path, outStationIdSet); |
| | |
| | | + softDeviationWeight * metrics.softDeviationCount; |
| | | |
| | | metrics.dynamicCost = |
| | | safeDouble(profileConfig.getS2BusyWeight(), 2.0d) * congWeightFactor * metrics.busyStationCount |
| | | 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.getS2RunBlockWeight(), 10.0d) * metrics.runBlockCount |
| | | + safeDouble(profileConfig.getS2LoopLoadWeight(), 12.0d) * metrics.loopPenalty; |
| | | return metrics; |
| | |
| | | return count; |
| | | } |
| | | |
| | | private int countBusyStationCount(List<Integer> stationIdList, Map<Integer, StationProtocol> statusMap) { |
| | | int count = 0; |
| | | for (Integer stationId : stationIdList) { |
| | | StationProtocol protocol = statusMap.get(stationId); |
| | | if (protocol != null && protocol.getTaskNo() != null && protocol.getTaskNo() > 0) { |
| | | count++; |
| | | } |
| | | private double calcCongestionScore(List<Integer> stationIdList, StationTrafficSnapshot trafficSnapshot) { |
| | | if (trafficSnapshot == null || trafficSnapshot.congestionScoreMap.isEmpty()) { |
| | | return 0.0d; |
| | | } |
| | | return count; |
| | | double score = 0.0d; |
| | | for (Integer stationId : stationIdList) { |
| | | score += trafficSnapshot.congestionScoreMap.getOrDefault(stationId, 0.0d); |
| | | } |
| | | return score; |
| | | } |
| | | |
| | | private double calcQueueDepthScore(List<Integer> stationIdList, StationTrafficSnapshot trafficSnapshot) { |
| | | if (trafficSnapshot == null || trafficSnapshot.queueDepthMap.isEmpty()) { |
| | | return 0.0d; |
| | | } |
| | | double score = 0.0d; |
| | | for (Integer stationId : stationIdList) { |
| | | score += trafficSnapshot.queueDepthMap.getOrDefault(stationId, 0); |
| | | } |
| | | return score; |
| | | } |
| | | |
| | | private double calcEstimatedWaitSeconds(List<Integer> stationIdList, StationTrafficSnapshot trafficSnapshot) { |
| | | if (trafficSnapshot == null || trafficSnapshot.estimatedWaitSecondsMap.isEmpty()) { |
| | | return 0.0d; |
| | | } |
| | | double score = 0.0d; |
| | | for (Integer stationId : stationIdList) { |
| | | score += trafficSnapshot.estimatedWaitSecondsMap.getOrDefault(stationId, 0.0d); |
| | | } |
| | | return score; |
| | | } |
| | | |
| | | private int countRunBlockCount(List<Integer> stationIdList, Map<Integer, StationProtocol> statusMap) { |
| | |
| | | return stationLoopLoadMap; |
| | | } |
| | | |
| | | private StationTrafficSnapshot loadStationTrafficSnapshot(Map<Integer, StationProtocol> statusMap) { |
| | | StationTrafficSnapshot snapshot = new StationTrafficSnapshot(); |
| | | Map<Integer, Integer> busyMap = new HashMap<>(); |
| | | Map<Integer, Integer> issuedReserveMap = new HashMap<>(); |
| | | Map<Integer, Integer> pendingQueueMap = new HashMap<>(); |
| | | |
| | | if (statusMap != null && !statusMap.isEmpty()) { |
| | | for (Map.Entry<Integer, StationProtocol> entry : statusMap.entrySet()) { |
| | | Integer stationId = entry.getKey(); |
| | | StationProtocol protocol = entry.getValue(); |
| | | if (stationId == null || protocol == null) { |
| | | continue; |
| | | } |
| | | if (protocol.getTaskNo() != null && protocol.getTaskNo() > 0) { |
| | | busyMap.put(stationId, 1); |
| | | } |
| | | } |
| | | } |
| | | |
| | | for (StationTaskTraceVo traceVo : loadActiveTraceList()) { |
| | | if (traceVo == null) { |
| | | continue; |
| | | } |
| | | List<Integer> pendingStationIds = distinctPositiveStationIds(traceVo.getPendingStationIds()); |
| | | List<Integer> issuedStationIds = distinctPositiveStationIds(traceVo.getLatestIssuedSegmentPath()); |
| | | Set<Integer> pendingSet = new HashSet<>(pendingStationIds); |
| | | for (Integer stationId : issuedStationIds) { |
| | | if (stationId == null || !pendingSet.contains(stationId)) { |
| | | continue; |
| | | } |
| | | increaseIntMap(issuedReserveMap, stationId, 1); |
| | | } |
| | | Set<Integer> issuedSet = new HashSet<>(issuedStationIds); |
| | | for (Integer stationId : pendingStationIds) { |
| | | if (stationId == null || issuedSet.contains(stationId)) { |
| | | continue; |
| | | } |
| | | increaseIntMap(pendingQueueMap, stationId, 1); |
| | | } |
| | | } |
| | | |
| | | Set<Integer> stationIdSet = new HashSet<>(); |
| | | stationIdSet.addAll(busyMap.keySet()); |
| | | stationIdSet.addAll(issuedReserveMap.keySet()); |
| | | stationIdSet.addAll(pendingQueueMap.keySet()); |
| | | if (statusMap != null) { |
| | | stationIdSet.addAll(statusMap.keySet()); |
| | | } |
| | | |
| | | for (Integer stationId : stationIdSet) { |
| | | if (stationId == null) { |
| | | continue; |
| | | } |
| | | int busyCount = busyMap.getOrDefault(stationId, 0); |
| | | int issuedReserveCount = issuedReserveMap.getOrDefault(stationId, 0); |
| | | int pendingQueueCount = pendingQueueMap.getOrDefault(stationId, 0); |
| | | boolean runBlock = false; |
| | | if (statusMap != null) { |
| | | StationProtocol protocol = statusMap.get(stationId); |
| | | runBlock = protocol != null && protocol.isRunBlock(); |
| | | } |
| | | |
| | | int queueDepth = issuedReserveCount + pendingQueueCount; |
| | | double congestionScore = busyCount * CONGESTION_BUSY_BASE |
| | | + issuedReserveCount * CONGESTION_ISSUED_RESERVE_BASE |
| | | + pendingQueueCount * CONGESTION_PENDING_QUEUE_BASE |
| | | + (runBlock ? CONGESTION_RUN_BLOCK_BASE : 0.0d); |
| | | double estimatedWaitSeconds = busyCount * WAIT_BUSY_SECONDS |
| | | + issuedReserveCount * WAIT_ISSUED_RESERVE_SECONDS |
| | | + pendingQueueCount * WAIT_PENDING_QUEUE_SECONDS |
| | | + (runBlock ? WAIT_RUN_BLOCK_SECONDS : 0.0d); |
| | | |
| | | if (queueDepth > 0) { |
| | | snapshot.queueDepthMap.put(stationId, queueDepth); |
| | | } |
| | | if (congestionScore > 0.0d) { |
| | | snapshot.congestionScoreMap.put(stationId, congestionScore); |
| | | } |
| | | if (estimatedWaitSeconds > 0.0d) { |
| | | snapshot.estimatedWaitSecondsMap.put(stationId, estimatedWaitSeconds); |
| | | } |
| | | } |
| | | return snapshot; |
| | | } |
| | | |
| | | private List<StationTaskTraceVo> loadActiveTraceList() { |
| | | if (stationTaskTraceRegistry == null) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<StationTaskTraceVo> traceList; |
| | | try { |
| | | traceList = stationTaskTraceRegistry.listLatestTraces(); |
| | | } catch (Exception ignore) { |
| | | return Collections.emptyList(); |
| | | } |
| | | if (traceList == null || traceList.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<StationTaskTraceVo> result = new ArrayList<>(); |
| | | for (StationTaskTraceVo traceVo : traceList) { |
| | | if (!isPlanningActiveTrace(traceVo)) { |
| | | continue; |
| | | } |
| | | result.add(traceVo); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private boolean isPlanningActiveTrace(StationTaskTraceVo traceVo) { |
| | | if (traceVo == null) { |
| | | return false; |
| | | } |
| | | String status = traceVo.getStatus(); |
| | | return StationTaskTraceRegistry.STATUS_WAITING.equals(status) |
| | | || StationTaskTraceRegistry.STATUS_RUNNING.equals(status) |
| | | || StationTaskTraceRegistry.STATUS_REROUTED.equals(status); |
| | | } |
| | | |
| | | private List<Integer> distinctPositiveStationIds(List<Integer> stationIdList) { |
| | | if (stationIdList == null || stationIdList.isEmpty()) { |
| | | return Collections.emptyList(); |
| | | } |
| | | List<Integer> result = new ArrayList<>(); |
| | | Set<Integer> seen = new HashSet<>(); |
| | | for (Integer stationId : stationIdList) { |
| | | if (stationId == null || stationId <= 0) { |
| | | continue; |
| | | } |
| | | if (seen.add(stationId)) { |
| | | result.add(stationId); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private void increaseIntMap(Map<Integer, Integer> target, Integer stationId, int delta) { |
| | | if (target == null || stationId == null || delta == 0) { |
| | | return; |
| | | } |
| | | target.put(stationId, target.getOrDefault(stationId, 0) + delta); |
| | | } |
| | | |
| | | 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 int turnCount; |
| | | private int liftTransferCount; |
| | | private int passOtherOutStationCount; |
| | | private int busyStationCount; |
| | | private double congestionScore; |
| | | private double queueDepthScore; |
| | | private double estimatedWaitSeconds; |
| | | private int runBlockCount; |
| | | private int softDeviationCount; |
| | | private double loopPenalty; |
| | |
| | | private double dynamicCost; |
| | | } |
| | | |
| | | private static class StationTrafficSnapshot { |
| | | 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 static class PathGlobalPolicy { |
| | | private double lenWeightFactor = 1.0d; |
| | | private double congWeightFactor = 1.0d; |