|
@@ -1,22 +1,22 @@
|
|
|
package com.rongwei.rwapsserver.aps.score;
|
|
|
|
|
|
-import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.date.DateUnit;
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import com.rongwei.rwapsserver.aps.domain.*;
|
|
|
-import com.rongwei.rwapsserver.aps.util.ApsConstants;
|
|
|
+import org.optaplanner.core.api.score.buildin.hardmediumsoft.HardMediumSoftScore;
|
|
|
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
|
|
|
import org.optaplanner.core.api.score.stream.*;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
-import static org.optaplanner.core.api.score.stream.ConstraintCollectors.count;
|
|
|
-
|
|
|
public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
|
|
|
private ZoneId zoneId = ZoneId.systemDefault();
|
|
@@ -28,17 +28,22 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
// noPreGbAfterNow(constraintFactory),
|
|
|
hasOnePreGbAfterNow(constraintFactory),
|
|
|
eqTimeCross(constraintFactory),
|
|
|
- deliveryDate(constraintFactory),
|
|
|
- seriesProduce(constraintFactory),
|
|
|
seriesProduceTimeWait(constraintFactory),
|
|
|
+ seriesProduceWashTimeWait(constraintFactory),
|
|
|
lzTimeLessMaxWait(constraintFactory),
|
|
|
equipmentRunTime(constraintFactory),
|
|
|
- balancedEqUse(constraintFactory),
|
|
|
+ eqTimeCrossTuihuo(constraintFactory),
|
|
|
|
|
|
+ deliveryDate(constraintFactory),
|
|
|
+ seriesProduce(constraintFactory),
|
|
|
seriesProduceWashingFurnace(constraintFactory),
|
|
|
- seriesProduceWashTimeWait(constraintFactory),
|
|
|
+ mergeTuihuo(constraintFactory),
|
|
|
+ sameEquipment(constraintFactory),
|
|
|
|
|
|
sameProcessSeries(constraintFactory),
|
|
|
+ processNear(constraintFactory),
|
|
|
+
|
|
|
+ // balancedEqUse(constraintFactory),
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -408,7 +413,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return bln;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(productionProcesses) -> 40)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(productionProcesses) -> 40)
|
|
|
.asConstraint("hasOnePreGbAfterNow");
|
|
|
}
|
|
|
|
|
@@ -462,7 +467,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return bol;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(proc1)->80)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(proc1)->80)
|
|
|
.asConstraint("equipmentRunTime");
|
|
|
}
|
|
|
|
|
@@ -500,7 +505,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return bol;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(proc1)->90)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(proc1)->90)
|
|
|
.asConstraint("lzTimeLessMaxWait");
|
|
|
}
|
|
|
|
|
@@ -525,7 +530,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return false;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(equipmentEquassociated, processess) -> {
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(equipmentEquassociated, processess) -> {
|
|
|
int washingFurnaceCount = seriesProduceWashingTimeFurnaceCount(processess);
|
|
|
return washingFurnaceCount*10;
|
|
|
})
|
|
@@ -620,7 +625,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return false;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(equipmentId,processes)->{
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(equipmentId,processes)->{
|
|
|
int counNum = seriesProduceTimeWaitCount(processes);
|
|
|
return counNum*10;
|
|
|
})
|
|
@@ -761,11 +766,15 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
if(proc1.getStartTime() == null || proc2.getStartTime() == null){
|
|
|
return false;
|
|
|
}
|
|
|
- Boolean b1 = (proc1.getStartTime().compareTo(proc2.getStartTime())<=0 && proc2.getStartTime().compareTo(proc1.getEndTime())<=0);
|
|
|
- Boolean b2 = (proc2.getStartTime().compareTo(proc1.getStartTime())<=0 && proc1.getStartTime().compareTo(proc2.getEndTime())<=0);
|
|
|
- return b1 || b2;
|
|
|
+ Boolean b1 = proc1.getEndTime().compareTo(proc2.getStartTime())<=0;
|
|
|
+ Boolean b2 = proc2.getEndTime().compareTo(proc1.getStartTime())<=0;
|
|
|
+ if(b1 || b2){
|
|
|
+ return false;
|
|
|
+ }else{
|
|
|
+ return true;
|
|
|
+ }
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(proc1,proc2)->100)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(proc1,proc2)->100)
|
|
|
.asConstraint("eqTimeCross");
|
|
|
}
|
|
|
|
|
@@ -779,23 +788,131 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
.filter(pro->{
|
|
|
return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退");
|
|
|
})
|
|
|
- .join(ProductionProcesses.class,Joiners.equal(ProductionProcesses::getEquipmentId))
|
|
|
- .filter((proc1,proc2)->{
|
|
|
- if(proc1.getId() == proc2.getId() ||
|
|
|
- (StrUtil.isNotBlank(proc1.getMergeProcessMark()) && StrUtil.isNotBlank(proc2.getMergeProcessMark()) && proc1.getMergeProcessMark().equals(proc2.getMergeProcessMark()))){
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
|
+ .filter((equipmentEquassociated,processes) -> {
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
+ Integer num = eqTimeCrossTuihuoCount(processes,"1");
|
|
|
+ if(num>0){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
return false;
|
|
|
- }
|
|
|
- if(proc1.getStartTime() == null || proc2.getStartTime() == null){
|
|
|
+ }else{
|
|
|
return false;
|
|
|
}
|
|
|
- Boolean b1 = (proc1.getStartTime().compareTo(proc2.getStartTime())<0 && proc2.getStartTime().compareTo(proc1.getEndTime())<0);
|
|
|
- Boolean b2 = (proc2.getStartTime().compareTo(proc1.getStartTime())<0 && proc1.getStartTime().compareTo(proc2.getEndTime())<0);
|
|
|
- return b1 || b2;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_HARD,(proc1,proc2)->100)
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(equipmentEquassociated,processes)->{
|
|
|
+ Integer num = eqTimeCrossTuihuoCount(processes,"2");
|
|
|
+ return num*100;
|
|
|
+ })
|
|
|
.asConstraint("eqTimeCrossTuihuo");
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 退火工序冲突计算
|
|
|
+ * @param processes
|
|
|
+ * @param type(1:是否存在冲突,2:冲突得分计算)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Integer eqTimeCrossTuihuoCount(List<ProductionProcesses> processes,String type){
|
|
|
+ int b = 0;
|
|
|
+ Equipment equipment = null;
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
+ equipment = processes.get(0).getEquipment();
|
|
|
+ }
|
|
|
+ List<ProductionProcesses> hasStartTimeProcess = processes.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
|
|
|
+ // 设备占用时间参与连续生产排程
|
|
|
+ if(equipment != null && equipment.getEquipmentRunTimes() != null && equipment.getEquipmentRunTimes().size()>0){
|
|
|
+ for (EquipmentRunTime equipmentRunTime : equipment.getEquipmentRunTimes()) {
|
|
|
+ ProductionProcesses pp = new ProductionProcesses();
|
|
|
+ pp.setStartTime(equipmentRunTime.getStartRunTime());
|
|
|
+ pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
|
|
|
+ pp.setProcessType(equipmentRunTime.getProcessType());
|
|
|
+ pp.setBsProcessesId(Arrays.asList(new String[]{"haspcprocess"}));
|
|
|
+ pp.setVolumeWidth(equipmentRunTime.getTotalVolumeWidth());
|
|
|
+ pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
|
|
|
+ if(equipmentRunTime.getOccupyType().equals("process")){
|
|
|
+ pp.setTaskType("processes");
|
|
|
+ }else {
|
|
|
+ pp.setTaskType("maintenance");
|
|
|
+ }
|
|
|
+ hasStartTimeProcess.add(pp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 按照开始时间排序
|
|
|
+ Collections.sort(hasStartTimeProcess, Comparator.comparing(ProductionProcesses::getSeriSort));
|
|
|
+ // 退火合并工序
|
|
|
+ Map<String,List<ProductionProcesses>> ppMap = new HashMap<>();
|
|
|
+ for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
|
+ ProductionProcesses prePro = hasStartTimeProcess.get(i);
|
|
|
+ ProductionProcesses nextPro = hasStartTimeProcess.get(i+1);
|
|
|
+ Map<String, String> conflictRoptions1 = prePro.getConflictRoptions();
|
|
|
+ Map<String, String> conflictRoptions2 = nextPro.getConflictRoptions();
|
|
|
+ if(conflictRoptions1.containsKey("hard-eqTimeCrossTuihuo")){
|
|
|
+ conflictRoptions1.remove("hard-eqTimeCrossTuihuo");
|
|
|
+ }
|
|
|
+ if(conflictRoptions2.containsKey("hard-eqTimeCrossTuihuo")){
|
|
|
+ conflictRoptions2.remove("hard-eqTimeCrossTuihuo");
|
|
|
+ }
|
|
|
+ // 开始时间相等为合并工序
|
|
|
+ if (prePro.getStartTime().compareTo(nextPro.getStartTime()) == 0){
|
|
|
+ if(prePro.getTaskType().equals("maintenance") || nextPro.getTaskType().equals("maintenance")){
|
|
|
+ if("2".equals(type)){
|
|
|
+// System.out.println("1:作业加工时间有交叉");
|
|
|
+ conflictRoptions1.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
|
|
|
+ conflictRoptions2.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
|
|
|
+ }
|
|
|
+ b++;
|
|
|
+ }else{
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String startTimeKey = prePro.getStartTime().format(formatter);
|
|
|
+ if(!ppMap.containsKey(startTimeKey)){
|
|
|
+ List<ProductionProcesses> pps = new ArrayList<>();
|
|
|
+ ppMap.put(startTimeKey,pps);
|
|
|
+ }
|
|
|
+ List<ProductionProcesses> processesList = ppMap.get(startTimeKey);
|
|
|
+ List<ProductionProcesses> preHas = processesList.stream().filter(v -> v.getId().equals(prePro.getId())).collect(Collectors.toList());
|
|
|
+ List<ProductionProcesses> nextHas = processesList.stream().filter(v -> v.getId().equals(nextPro.getId())).collect(Collectors.toList());
|
|
|
+ if(preHas == null || preHas.size() == 0){
|
|
|
+ processesList.add(prePro);
|
|
|
+ }
|
|
|
+ if(nextHas == null || nextHas.size() == 0){
|
|
|
+ processesList.add(nextPro);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ if(prePro.getEndTime().compareTo(nextPro.getStartTime()) == 1){
|
|
|
+ if("2".equals(type)){
|
|
|
+// System.out.println("1:作业加工时间有交叉");
|
|
|
+ conflictRoptions1.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
|
|
|
+ conflictRoptions2.put("hard-eqTimeCrossTuihuo","作业加工时间有交叉");
|
|
|
+ }
|
|
|
+ b++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 检查合并工序是否超过容量
|
|
|
+ for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
|
|
|
+ List<ProductionProcesses> v = entry.getValue();
|
|
|
+ BigDecimal totalWidth = new BigDecimal("0");
|
|
|
+ BigDecimal totalWeight = new BigDecimal("0");
|
|
|
+ for (ProductionProcesses productionProcesses : v) {
|
|
|
+ totalWidth = totalWidth.add(productionProcesses.getVolumeWidth()).add(productionProcesses.getEquipment().getEquipmentParameter().getFurnace());
|
|
|
+ totalWeight = totalWeight.add(productionProcesses.getSinglerollweight());
|
|
|
+ }
|
|
|
+ if(totalWidth.compareTo(v.get(0).getEquipment().getEquipmentParameter().getEquipmentWidth())>0
|
|
|
+ || totalWeight.compareTo(v.get(0).getEquipment().getEquipmentParameter().getEquipmentBearing())>0){
|
|
|
+ if("2".equals(type)){
|
|
|
+// System.out.println("1:作业加工时间有交叉");
|
|
|
+ for (ProductionProcesses productionProcesses : v) {
|
|
|
+ productionProcesses.getConflictRoptions().put("hard-eqTimeCrossTuihuo","合并的作业超出设备容量");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ b++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return b;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 软约束:交货日期,根据延迟交货日期的天数来做惩罚分数计算
|
|
|
* @param constraintFactory
|
|
@@ -803,12 +920,13 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
*/
|
|
|
private Constraint deliveryDate(ConstraintFactory constraintFactory) {
|
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(productionProcesses -> productionProcesses.getNextProcesses() == null)
|
|
|
.filter(productionProcesses -> {
|
|
|
/*
|
|
|
获取最后一步工步的结束时间(最后一步工步的结束时间即此产品生产的实际结束时间)
|
|
|
并且获取结束时间大于生产订单的交货日期
|
|
|
*/
|
|
|
- if(productionProcesses.getEndTime() == null || productionProcesses.getNextProcesses() == null){
|
|
|
+ if(productionProcesses.getEndTime() == null){
|
|
|
return false;
|
|
|
}
|
|
|
// 取最小订单交货日期
|
|
@@ -826,7 +944,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
productionProcesses.getEndTime().atZone(zoneId).toInstant().toEpochMilli()>deliveryMinDate.getTime();
|
|
|
return bol;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_SOFT,(productionProcesses) ->{
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(productionProcesses) ->{
|
|
|
Date deliveryMinDate = null;
|
|
|
for (ProduceOrder produceOrder : productionProcesses.getProduceOrder()) {
|
|
|
if(deliveryMinDate == null){
|
|
@@ -864,7 +982,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return isbalance;
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_SOFT,(taskType, processess) -> {
|
|
|
+ .penalize(HardMediumSoftScore.ONE_SOFT,(taskType, processess) -> {
|
|
|
Integer balanceNum = balanceCount(processess);
|
|
|
return balanceNum;
|
|
|
})
|
|
@@ -946,7 +1064,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return false;*/
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_SOFT,(equipmentId,processes)->{
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
|
|
|
int countNum = seriesProduceCount(processes);
|
|
|
return countNum*100;
|
|
|
})
|
|
@@ -986,13 +1104,23 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
|
if(hasStartTimeProcess.get(i).getSeriesProduceMark() != null && hasStartTimeProcess.get(i+1).getSeriesProduceMark() != null){
|
|
|
+ Map<String, String> conflictRoptions1 = hasStartTimeProcess.get(i).getConflictRoptions();
|
|
|
+ Map<String, String> conflictRoptions2 = hasStartTimeProcess.get(i+1).getConflictRoptions();
|
|
|
if("铸轧".equals(hasStartTimeProcess.get(i).getProcessType())){
|
|
|
+ if(conflictRoptions1.containsKey("soft-seriesProduceZz")){
|
|
|
+ conflictRoptions1.remove("soft-seriesProduceZz");
|
|
|
+ }
|
|
|
+ if(conflictRoptions2.containsKey("soft-seriesProduceZz")){
|
|
|
+ conflictRoptions2.remove("soft-seriesProduceZz");
|
|
|
+ }
|
|
|
String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
|
|
|
String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
|
|
|
if(serspre.length == 5 && sersafter.length == 5){
|
|
|
// 合金不同或者产品类型不同则需要换辊和立板
|
|
|
if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
|
|
|
b = b+2;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反换辊和立板的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反换辊和立板的连续约束");
|
|
|
}else{
|
|
|
// 合金相同情况下后面的宽度大于前面的宽度需要换辊和立板
|
|
|
// 合金相同情况下后面的宽度小于前面的宽度需要立板
|
|
@@ -1004,8 +1132,12 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
BigDecimal i2 = new BigDecimal(s2);
|
|
|
if(i1.compareTo(i2)<0){
|
|
|
b = b+2;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反换辊和立板的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反换辊和立板的连续约束");
|
|
|
}else if(i1.compareTo(i2)>0){
|
|
|
b++;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceZz","和后一道工序违反立板的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceZz","和前一道工序违反立板的连续约束");
|
|
|
}
|
|
|
}catch (Exception e){
|
|
|
e.printStackTrace();
|
|
@@ -1013,6 +1145,12 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
}
|
|
|
} else if ("冷轧".equals(hasStartTimeProcess.get(i).getProcessType())) {
|
|
|
+ if(conflictRoptions1.containsKey("soft-seriesProduceLz")){
|
|
|
+ conflictRoptions1.remove("soft-seriesProduceLz");
|
|
|
+ }
|
|
|
+ if(conflictRoptions2.containsKey("soft-seriesProduceLz")){
|
|
|
+ conflictRoptions2.remove("soft-seriesProduceLz");
|
|
|
+ }
|
|
|
String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
|
|
|
String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
|
|
|
// 前后道所属作业ID
|
|
@@ -1021,6 +1159,8 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
if(serspre.length == 5 && sersafter.length == 5){
|
|
|
if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
|
|
|
b = b+10;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
|
|
|
}else{
|
|
|
// 前道工序宽度、输入物料厚度、输出物料厚度
|
|
|
String s1 = serspre[2];
|
|
@@ -1036,10 +1176,14 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
// 后端工序大于前道工序,并且大于30mm
|
|
|
if((i1.add(new BigDecimal("30"))).compareTo(i2)<0){
|
|
|
b = b+6;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
|
|
|
}
|
|
|
// 后端工序大于前道工序,并且小于30mm
|
|
|
else if(i1.compareTo(i2)<0 && (i1.add(new BigDecimal("30"))).compareTo(i2)>=0){
|
|
|
b = b+5;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceLz","和后一道工序违反换辊的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceLz","和前一道工序违反换辊的连续约束");
|
|
|
}
|
|
|
// 后端工序小于前道工序
|
|
|
else if(i1.compareTo(i2)>0){
|
|
@@ -1096,9 +1240,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
}
|
|
|
return false;*/
|
|
|
})
|
|
|
- .penalize(HardSoftScore.ONE_SOFT,(equipmentEquassociated, processess) -> {
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentEquassociated, processess) -> {
|
|
|
int washingFurnaceCount = seriesProduceWashingFurnaceCount(processess);
|
|
|
- return washingFurnaceCount*10000;
|
|
|
+ return washingFurnaceCount*100;
|
|
|
})
|
|
|
.asConstraint("seriesProduceWashingFurnace");
|
|
|
}
|
|
@@ -1148,6 +1292,14 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
int notSeriesNum = 0;
|
|
|
// 评分计算
|
|
|
for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
|
+ Map<String, String> conflictRoptions1 = hasStartTimeProcess.get(i).getConflictRoptions();
|
|
|
+ Map<String, String> conflictRoptions2 = hasStartTimeProcess.get(i+1).getConflictRoptions();
|
|
|
+ if(conflictRoptions1.containsKey("soft-seriesProduceWashingFurnaceZz")){
|
|
|
+ conflictRoptions1.remove("soft-seriesProduceWashingFurnaceZz");
|
|
|
+ }
|
|
|
+ if(conflictRoptions2.containsKey("soft-seriesProduceWashingFurnaceZz")){
|
|
|
+ conflictRoptions2.remove("soft-seriesProduceWashingFurnaceZz");
|
|
|
+ }
|
|
|
List<WashingMetal> closealloynames = hasStartTimeProcess.get(i).getApsOverallConfig().getClosealloynames();
|
|
|
if(closealloynames != null && closealloynames.size()>0){
|
|
|
for (WashingMetal closealloyname : closealloynames) {
|
|
@@ -1155,6 +1307,8 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
if(closealloyname.getProcessmetals().contains(hasStartTimeProcess.get(i).getVolumeMetal())
|
|
|
&& closealloyname.getNextprocessmetals().contains(hasStartTimeProcess.get(i+1).getVolumeMetal())){
|
|
|
notSeriesNum++;
|
|
|
+ conflictRoptions1.put("soft-seriesProduceWashingFurnaceZz","和后一道工序违反洗炉的连续约束");
|
|
|
+ conflictRoptions2.put("soft-seriesProduceWashingFurnaceZz","和前一道工序违反洗炉的连续约束");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -1176,7 +1330,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
&& !"成退".equals(process.getProcessType()) && !"中退".equals(process.getProcessType());
|
|
|
})
|
|
|
.groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
|
- .penalize(HardSoftScore.ONE_SOFT,(equipmentId, processess) -> {
|
|
|
+ .penalize(HardMediumSoftScore.ONE_SOFT,(equipmentId, processess) -> {
|
|
|
int notSeriesNum = 0;
|
|
|
List<ProductionProcesses> hasStartTimeProcess = processess.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
|
|
|
// 根据开始时间排序
|
|
@@ -1193,4 +1347,144 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
|
})
|
|
|
.asConstraint("sameProcessSeries");
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 排程时间尽量靠前
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint processNear(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter((process)->{
|
|
|
+ if(process.getPreviousProcesses() == null || process.getPreviousProcesses().size() == 0){
|
|
|
+ if(process.getStartTime().compareTo(process.getApsOverallConfig().getStartTime())>0){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ ProductionProcesses preProcess = process.getPreviousProcesses().get(0);
|
|
|
+ // 流转时间
|
|
|
+ Integer lzTimes = 0;
|
|
|
+ if(preProcess != null){
|
|
|
+ if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(process.getEquipment().getWorkshopid())){
|
|
|
+ lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
|
|
|
+ }else{
|
|
|
+ lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
|
|
|
+ }
|
|
|
+ // 最小等待时间对比流转时间
|
|
|
+ if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
|
|
|
+ lzTimes = preProcess.getMinWaitTime();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
|
|
|
+ if(process.getStartTime().compareTo(minStartTime)>0){
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_SOFT,(process) -> {
|
|
|
+ int processNearNum = 0;
|
|
|
+ if(process.getPreviousProcesses() == null || process.getPreviousProcesses().size() == 0){
|
|
|
+ processNearNum = (int)ChronoUnit.MINUTES.between(process.getApsOverallConfig().getStartTime(), process.getStartTime());
|
|
|
+ }else{
|
|
|
+ ProductionProcesses preProcess = process.getPreviousProcesses().get(0);
|
|
|
+ // 流转时间
|
|
|
+ Integer lzTimes = 0;
|
|
|
+ if(preProcess != null){
|
|
|
+ if(preProcess.getEquipment().getWorkshopid() != null && preProcess.getEquipment().getWorkshopid().equals(process.getEquipment().getWorkshopid())){
|
|
|
+ lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_IN");
|
|
|
+ }else{
|
|
|
+ lzTimes = process.getApsOverallConfig().getRoamTime().get("WORKSHOP_CROSS");
|
|
|
+ }
|
|
|
+ // 最小等待时间对比流转时间
|
|
|
+ if(preProcess.getMinWaitTime() != null && lzTimes<preProcess.getMinWaitTime()){
|
|
|
+ lzTimes = preProcess.getMinWaitTime();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LocalDateTime minStartTime = preProcess.getEndTime().plusMinutes(lzTimes);
|
|
|
+ processNearNum = (int)ChronoUnit.MINUTES.between(minStartTime, process.getStartTime());
|
|
|
+ }
|
|
|
+ return processNearNum;
|
|
|
+ })
|
|
|
+ .asConstraint("processNear");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 退火工序优先合并
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint mergeTuihuo(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .filter(pro->{
|
|
|
+ return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退");
|
|
|
+ })
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
|
+ .filter((equipmentId,processes) -> {
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
|
|
|
+ // 退火合并工序
|
|
|
+ Map<String,List<ProductionProcesses>> ppMap = new HashMap<>();
|
|
|
+ for(int i=0;i<processes.size()-1;i++){
|
|
|
+ ProductionProcesses prePro = processes.get(i);
|
|
|
+ ProductionProcesses nextPro = processes.get(i+1);
|
|
|
+ // 开始时间相等为合并工序
|
|
|
+ if (prePro.getStartTime().compareTo(nextPro.getStartTime()) == 0){
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ String startTimeKey = prePro.getStartTime().format(formatter);
|
|
|
+ if(!ppMap.containsKey(startTimeKey)){
|
|
|
+ List<ProductionProcesses> pps = new ArrayList<>();
|
|
|
+ ppMap.put(startTimeKey,pps);
|
|
|
+ }
|
|
|
+ List<ProductionProcesses> processesList = ppMap.get(startTimeKey);
|
|
|
+ List<ProductionProcesses> preHas = processesList.stream().filter(v -> v.getId().equals(prePro.getId())).collect(Collectors.toList());
|
|
|
+ List<ProductionProcesses> nextHas = processesList.stream().filter(v -> v.getId().equals(nextPro.getId())).collect(Collectors.toList());
|
|
|
+ if(preHas == null || preHas.size() == 0){
|
|
|
+ processesList.add(prePro);
|
|
|
+ }
|
|
|
+ if(nextHas == null || nextHas.size() == 0){
|
|
|
+ processesList.add(nextPro);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return ppMap.size()*10000;
|
|
|
+ })
|
|
|
+ .asConstraint("mergeTuihuo");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 相同作业放在同一设备上加工
|
|
|
+ * @param constraintFactory
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private Constraint sameEquipment(ConstraintFactory constraintFactory){
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
+ .groupBy(ProductionProcesses::getUniqueBsProcessesId,ConstraintCollectors.toList())
|
|
|
+ .filter((equipmentEquassociated,processes) -> {
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
+ return true;
|
|
|
+ }else{
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(uniqueBsProcessesId,processes)->{
|
|
|
+ /*if(uniqueBsProcessesId.equals("8aa1d524436149859623a6a67a4af6c0")){
|
|
|
+ System.out.println("*********************************");
|
|
|
+ for (ProductionProcesses process : processes) {
|
|
|
+ System.out.println(process.getEquipmentId());
|
|
|
+ }
|
|
|
+ System.out.println("*********************************");
|
|
|
+ }*/
|
|
|
+ Map<String, List<ProductionProcesses>> listMap = processes.stream().collect(Collectors.groupingBy(ProductionProcesses::getEquipmentId));
|
|
|
+ return listMap.size()*1000;
|
|
|
+ })
|
|
|
+ .asConstraint("sameEquipment");
|
|
|
+ }
|
|
|
}
|