浏览代码

APS平台新模型约束优化

fangpy 1 年之前
父节点
当前提交
38e6d718cb

+ 26 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/domain/ProductionProcesses.java

@@ -191,6 +191,16 @@ public class ProductionProcesses extends Step{
      */
     private Integer orderMark;
 
+    /**
+     * 是否冲突
+     */
+    private String hasConflict;
+
+    /**
+     * 冲突描述
+     */
+    private String conflictDes;
+
     public String getEquipmentType() {
         return equipmentType;
     }
@@ -479,4 +489,20 @@ public class ProductionProcesses extends Step{
     public void setOrderMark(Integer orderMark) {
         this.orderMark = orderMark;
     }
+
+    public String getHasConflict() {
+        return hasConflict;
+    }
+
+    public void setHasConflict(String hasConflict) {
+        this.hasConflict = hasConflict;
+    }
+
+    public String getConflictDes() {
+        return conflictDes;
+    }
+
+    public void setConflictDes(String conflictDes) {
+        this.conflictDes = conflictDes;
+    }
 }

+ 66 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/listener/TaskStartTimeListener.java

@@ -7,6 +7,7 @@ import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
 import org.optaplanner.core.api.domain.variable.VariableListener;
 import org.optaplanner.core.api.score.director.ScoreDirector;
 import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 
 /**
@@ -70,18 +71,81 @@ public class TaskStartTimeListener implements VariableListener<ApsSolution, Prod
         }*/
     }
 
+    /**
+     * 级联更新下一个任务的开始时间、结束时间
+     * @param scoreDirector
+     * @param process
+     */
     private void setNextAllStartTime(ScoreDirector<ApsSolution> scoreDirector,ProductionProcesses process){
         LocalDateTime startDateTime = startTimeSet(process);
         scoreDirector.beforeVariableChanged(process, "startTime");
         process.setStartTime(startDateTime);
-        // 设备占用的任务设置
-//        equipmentProListSet(process);
         scoreDirector.afterVariableChanged(process, "startTime");
         if(process.getNextProcesses() != null && process.getNextProcesses().size()>0){
             for (ProductionProcesses nextProcess : process.getNextProcesses()) {
                 setNextAllStartTime(scoreDirector,nextProcess);
             }
         }
+        // 前置任务最大等待时间修正
+        preProcessCheck(scoreDirector,process);
+    }
+
+    private void preProcessCheck(ScoreDirector<ApsSolution> scoreDirector,ProductionProcesses process){
+        if(process.getPreviousProcesses() != null && process.getPreviousProcesses().size()>1){
+            for (ProductionProcesses previousProcess : process.getPreviousProcesses()) {
+                if(previousProcess.getMaxWaitTime() != null && previousProcess.getMaxWaitTime()>0){
+                    if(previousProcess.getStartTime() == null || previousProcess.getEndTime() == null || process.getStartTime() == null){
+                        continue;
+                    }
+                    // 前一工序作业加上最大等待时间小于当前作业的开始时间
+                    if(previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime()).compareTo(process.getStartTime())<0){
+                        long betweenMinutes =  ChronoUnit.MINUTES.between(previousProcess.getEndTime().plusMinutes(previousProcess.getMaxWaitTime()) , process.getStartTime());
+                        List<EquipmentRunTime> zyTimes = getZyTime(previousProcess);
+                        LocalDateTime startTime = previousProcess.getStartTime().plusMinutes(betweenMinutes+1);
+                        LocalDateTime endTime = previousProcess.getEndTime().plusMinutes(betweenMinutes+1);
+                        if(zyTimes != null && zyTimes.size()>0){
+                            for (EquipmentRunTime zyTime : zyTimes) {
+                                if(startTime.compareTo(zyTime.getEndRunTime())>0 || endTime.compareTo(zyTime.getStartRunTime())<0){
+                                    continue;
+                                }else{
+                                    startTime = zyTime.getEndRunTime().plusMinutes(1);
+                                    endTime = startTime.plusMinutes(previousProcess.getProduceTime());
+                                }
+                            }
+                        }
+                        scoreDirector.beforeVariableChanged(process, "startTime");
+                        previousProcess.setStartTime(startTime);
+                        scoreDirector.afterVariableChanged(process, "startTime");
+                    }
+                }
+            }
+        }
+    }
+
+    private List<EquipmentRunTime> getZyTime(ProductionProcesses process){
+        List<EquipmentRunTime> equipmentRunTimes = process.getEquipment().getEquipmentRunTimes();
+        List<EquipmentRunTime> allRunTimes = new ArrayList<>();
+        if(equipmentRunTimes != null && equipmentRunTimes.size()>0){
+            for (EquipmentRunTime equipmentRunTime : equipmentRunTimes) {
+                EquipmentRunTime copy = new EquipmentRunTime();
+                copy.setStartRunTime(equipmentRunTime.getStartRunTime());
+                copy.setEndRunTime(equipmentRunTime.getEndRunTime());
+                allRunTimes.add(copy);
+            }
+        }
+        if(process.getEquipment().getProcessesList() != null && process.getEquipment().getProcessesList().size()>0){
+            for (ProductionProcesses productionProcesses : process.getEquipment().getProcessesList()) {
+                if(productionProcesses.getStartTime() != null && productionProcesses.getEndTime() != null){
+                    EquipmentRunTime copy = new EquipmentRunTime();
+                    copy.setStartRunTime(productionProcesses.getStartTime());
+                    copy.setEndRunTime(productionProcesses.getEndTime());
+                    allRunTimes.add(copy);
+                }
+            }
+        }
+        // 按照开始时间排序
+        allRunTimes.sort(Comparator.comparing(EquipmentRunTime::getStartRunTime));
+        return allRunTimes;
     }
 
     /**

+ 43 - 2
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/service/impl/ProductionScheduleServiceImpl.java

@@ -6,10 +6,13 @@ import com.rongwei.rwapsserver.aps.domain.Equipment;
 import com.rongwei.rwapsserver.aps.domain.ProductionProcesses;
 import com.rongwei.rwapsserver.aps.score.ApsConstraintProvider;
 import com.rongwei.rwapsserver.aps.service.ProductionScheduleService;
+import com.rongwei.rwapsserver.aps.util.ApsConstants;
 import com.rongwei.rwapsserver.aps.util.ApsException;
 import com.rongwei.rwapsserver.aps.vo.ProductionScheduleRetVo;
 import com.rongwei.rwapsserver.aps.vo.ProductionScheduleVo;
+import org.optaplanner.core.api.score.ScoreExplanation;
 import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
+import org.optaplanner.core.api.score.constraint.ConstraintMatch;
 import org.optaplanner.core.api.solver.SolutionManager;
 import org.optaplanner.core.api.solver.Solver;
 import org.optaplanner.core.api.solver.SolverFactory;
@@ -42,7 +45,7 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         // 排程运行时长
         Integer planSeconds = productionScheduleVo.getPlanSeconds();
         if(planSeconds == null || planSeconds <= 0){
-            planSeconds = 300;
+            planSeconds = 60;
         }
 
         // optaplanner 求解器配置实例化
@@ -63,7 +66,8 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
         System.out.println("*****************************");
 //        System.out.println(solvedBalance);
         SolutionManager<ApsSolution, HardSoftScore> scoreManager = SolutionManager.create(solverFactory);
-        System.out.println(scoreManager.explain(solvedBalance));
+        ScoreExplanation<ApsSolution, HardSoftScore> explain = scoreManager.explain(solvedBalance);
+        System.out.println(explain);
         System.out.println("*****************************");
         productionScheduleRetVo.setScoreResult(scoreManager.explain(solvedBalance).toString());
 
@@ -74,10 +78,47 @@ public class ProductionScheduleServiceImpl implements ProductionScheduleService
             productionProcesses.getEquipment().setProcessesList(null);
             productionProcesses.setPreviousStep(null);
         }
+        // 得分分析
+        softExplain(explain,solvedBalance.getProcessesList());
         productionScheduleRetVo.setProcesses(solvedBalance.getProcessesList());
         return productionScheduleRetVo;
     }
 
+    /**
+     * 最终得分分析
+     * @param explain
+     * @param processes
+     */
+    private void softExplain(ScoreExplanation<ApsSolution, HardSoftScore> explain,List<ProductionProcesses> processes){
+        if(explain != null && explain.getConstraintMatchTotalMap() != null && explain.getConstraintMatchTotalMap().size()>0){
+            explain.getConstraintMatchTotalMap().forEach((k,v)->{
+                String constraintName = v.getConstraintName();
+                if(constraintName != null){
+                    String desc = ApsConstants.constraintDesc.get(constraintName);
+                    if(desc != null && v.getConstraintMatchSet() != null && v.getConstraintMatchSet().size()>0){
+                        for (ConstraintMatch<HardSoftScore> hardSoftScoreConstraintMatch : v.getConstraintMatchSet()) {
+                            if(hardSoftScoreConstraintMatch.getIndictedObjectList() != null && hardSoftScoreConstraintMatch.getIndictedObjectList().size() > 0){
+                                for (Object o : hardSoftScoreConstraintMatch.getIndictedObjectList()) {
+                                    if(o instanceof ProductionProcesses){
+                                        ProductionProcesses productionProcesses = (ProductionProcesses)o;
+                                        productionProcesses.setHasConflict("y");
+                                        productionProcesses.setConflictDes(desc);
+                                    } else if (o instanceof ArrayList) {
+                                        List<ProductionProcesses> processesList = (ArrayList)o;
+                                        for (ProductionProcesses productionProcesses : processesList) {
+                                            productionProcesses.setHasConflict("y");
+                                            productionProcesses.setConflictDes(desc);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            });
+        }
+    }
+
     /**
      * 业务数据模型转换前置处理
      * @param productionScheduleVo

+ 16 - 0
rw-aps-server/src/main/java/com/rongwei/rwapsserver/aps/util/ApsConstants.java

@@ -1,7 +1,23 @@
 package com.rongwei.rwapsserver.aps.util;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public class ApsConstants {
 
     public final static String EQUIPMENTTYPE_TUIHUOLU = "退火炉";
 
+    public final static Map<String,String> constraintDesc = new HashMap<>();
+
+    static {
+        constraintDesc.put("eqTypeSame","工序作业所需的设备必须在工序的可选设备之内");
+        constraintDesc.put("noPreGbAfterNow","第一步工序作业要小于开始排程时间");
+        constraintDesc.put("hasOnePreGbAfterNow","当前工序作业开始时间违反上一步工序作业最大等待时间限制");
+        constraintDesc.put("equipmentRunTime","设备已排产时间段不可排产其它工序作业");
+        constraintDesc.put("lzTimeLessMaxWait","上一工序作业流转时间不能大于上一工序作业最大等待时间");
+        constraintDesc.put("eqTimeCross","排程过程中出现相同设备排产时间段有交叉");
+        constraintDesc.put("deliveryDate","订单交货期不满足");
+        constraintDesc.put("seriesProduce","订单的连续生产要求不满足");
+    }
+
 }