|
@@ -9,6 +9,7 @@ import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
|
|
import org.optaplanner.core.api.score.stream.*;
|
|
import org.optaplanner.core.api.score.stream.*;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
import java.math.BigDecimal;
|
|
|
|
+import java.math.RoundingMode;
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
import java.time.ZoneId;
|
|
import java.time.ZoneId;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.format.DateTimeFormatter;
|
|
@@ -34,6 +35,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
seriesProduceWashTimeWait(constraintFactory),
|
|
seriesProduceWashTimeWait(constraintFactory),
|
|
equipmentRunTime(constraintFactory),
|
|
equipmentRunTime(constraintFactory),
|
|
eqTimeCrossTuihuo(constraintFactory),
|
|
eqTimeCrossTuihuo(constraintFactory),
|
|
|
|
+ eqTimeCrossMinTuihuo(constraintFactory),
|
|
|
|
|
|
deliveryDate(constraintFactory),
|
|
deliveryDate(constraintFactory),
|
|
seriesProduce(constraintFactory),
|
|
seriesProduce(constraintFactory),
|
|
@@ -41,9 +43,14 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
mergeTuihuo(constraintFactory),
|
|
mergeTuihuo(constraintFactory),
|
|
sameEquipment(constraintFactory),
|
|
sameEquipment(constraintFactory),
|
|
|
|
|
|
|
|
+ processLzNear(constraintFactory),
|
|
|
|
+ processBtNear(constraintFactory),
|
|
|
|
+ seriesZzLb(constraintFactory),
|
|
|
|
+
|
|
|
|
+
|
|
// sameProcessSeries(constraintFactory),
|
|
// sameProcessSeries(constraintFactory),
|
|
processNear(constraintFactory),
|
|
processNear(constraintFactory),
|
|
-
|
|
|
|
|
|
+ eqTimeCrossMinTuihuoSoft(constraintFactory),
|
|
// balancedEqUse(constraintFactory),
|
|
// balancedEqUse(constraintFactory),
|
|
};
|
|
};
|
|
}
|
|
}
|
|
@@ -201,7 +208,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
private Constraint equipmentRunTime(ConstraintFactory constraintFactory) {
|
|
private Constraint equipmentRunTime(ConstraintFactory constraintFactory) {
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
.filter(pro->{
|
|
.filter(pro->{
|
|
- return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退");
|
|
|
|
|
|
+ return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退") && !pro.getProcessType().equals("小卷成退");
|
|
})
|
|
})
|
|
.filter(productionProcesses -> {
|
|
.filter(productionProcesses -> {
|
|
boolean bol = false;
|
|
boolean bol = false;
|
|
@@ -403,6 +410,163 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
.asConstraint("seriesProduceTimeWait");
|
|
.asConstraint("seriesProduceTimeWait");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 铸轧预留连续排产时间
|
|
|
|
+ * @param constraintFactory
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Constraint seriesZzLb(ConstraintFactory constraintFactory) {
|
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
|
+ .filter((processe) -> {
|
|
|
|
+ return "铸轧".equals(processe.getProcessType());
|
|
|
|
+ })
|
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId, ConstraintCollectors.toList())
|
|
|
|
+ .filter((equipmentId,processes) -> {
|
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
|
+ for (ProductionProcesses process : processes) {
|
|
|
|
+ if(process.getConflictRoptions().containsKey("soft-seriesZzLb")){
|
|
|
|
+ process.getConflictRoptions().remove("soft-seriesZzLb");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ /*int counNum = seriesProduceTimeWaitCount(processes);
|
|
|
|
+ if(counNum>0){
|
|
|
|
+ return true;
|
|
|
|
+ }*/
|
|
|
|
+ return false;
|
|
|
|
+ })
|
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processes)->{
|
|
|
|
+ int counNum = seriesZzLbCount(processes);
|
|
|
|
+ return counNum*1000;
|
|
|
|
+ })
|
|
|
|
+ .asConstraint("seriesZzLb");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int seriesZzLbCount(List<ProductionProcesses> processes){
|
|
|
|
+ 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.setEndTime(equipmentRunTime.getEndRunTime());
|
|
|
|
+ pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipmentRunTime.getProcessType());
|
|
|
|
+ pp.setPrepressworkmin(equipmentRunTime.getPrepressworkmin() == null ? 0 : equipmentRunTime.getPrepressworkmin());
|
|
|
|
+ pp.setCutfinishmin(equipmentRunTime.getCutfinishmin() == null ? 0 : equipmentRunTime.getCutfinishmin());
|
|
|
|
+ pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ pp.setProduceTime(equipmentRunTime.getOnceprocessmin());
|
|
|
|
+ pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
|
|
|
|
+ pp.setLastSerialLbWeight(equipmentRunTime.getLastSerialLbWeight());
|
|
|
|
+ hasStartTimeProcess.add(pp);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 按照开始时间排序
|
|
|
|
+ Collections.sort(hasStartTimeProcess, Comparator.comparing(ProductionProcesses::getSeriSort));
|
|
|
|
+ // 获取设备已排程好的最后一个作业,计算连续加工
|
|
|
|
+ if(equipment.getLastProcessType() != null && equipment.getLastSeriesProduceMark() != null){
|
|
|
|
+ ProductionProcesses pp = new ProductionProcesses();
|
|
|
|
+ pp.setSeriesProduceMark(equipment.getLastSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipment.getLastProcessType());
|
|
|
|
+ pp.setCutfinishmin(equipment.getLastProcessCutfinishmin() == null ? 0 : equipment.getLastProcessCutfinishmin());
|
|
|
|
+ pp.setEndTime(equipment.getLastProcessEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
|
|
|
+ pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
|
|
+ pp.setProduceTime(equipment.getOnceprocessmin());
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ pp.setLastSerialLbWeight(equipment.getLastSerialLbWeight());
|
|
|
|
+ hasStartTimeProcess.add(0,pp);
|
|
|
|
+ }
|
|
|
|
+ for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getId() == null && hasStartTimeProcess.get(i).getId() == null){
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ ProductionProcesses prePro = hasStartTimeProcess.get(i);
|
|
|
|
+ ProductionProcesses nextPro = hasStartTimeProcess.get(i+1);
|
|
|
|
+ Map<String, String> conflictRoptions1 = prePro.getConflictRoptions();
|
|
|
|
+ Map<String, String> conflictRoptions2 = nextPro.getConflictRoptions();
|
|
|
|
+ if(hasStartTimeProcess.get(i).getSeriesProduceMark() != null && hasStartTimeProcess.get(i+1).getSeriesProduceMark() != null){
|
|
|
|
+ // 周期立板已连续生产吨数
|
|
|
|
+ BigDecimal zqlb = new BigDecimal("0");
|
|
|
|
+ if(!hasStartTimeProcess.get(i).getSeriesProduceMark().equals(hasStartTimeProcess.get(i+1).getSeriesProduceMark())){
|
|
|
|
+ String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
|
|
|
|
+ String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
|
|
|
|
+ // 换辊时长(分钟)
|
|
|
|
+ int jgtime = hasStartTimeProcess.get(i).getCutfinishmin() + hasStartTimeProcess.get(i+1).getPrepressworkmin();
|
|
|
|
+ // 立板时长(分钟)
|
|
|
|
+ int standingtime = hasStartTimeProcess.get(i).getApsOverallConfig().getStandingtime()*60;
|
|
|
|
+ // 周期立板最大重量
|
|
|
|
+ Integer standingyield = hasStartTimeProcess.get(i).getApsOverallConfig().getStandingyield();
|
|
|
|
+ BigDecimal standingyieldbig = new BigDecimal(standingyield);
|
|
|
|
+ // 取最大值
|
|
|
|
+ int maxTime = jgtime;
|
|
|
|
+ if(standingtime>jgtime){
|
|
|
|
+ maxTime = standingtime;
|
|
|
|
+ }
|
|
|
|
+ // 周期立板总重量统计
|
|
|
|
+ if(zqlb.compareTo(new BigDecimal("0")) == 0){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getLastSerialLbWeight() != null){
|
|
|
|
+ zqlb = hasStartTimeProcess.get(i).getLastSerialLbWeight();
|
|
|
|
+ }else{
|
|
|
|
+ zqlb = hasStartTimeProcess.get(i).getSinglerollweight();
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ zqlb = zqlb.add(hasStartTimeProcess.get(i).getSinglerollweight());
|
|
|
|
+ }
|
|
|
|
+ // 周期立板剩余时间
|
|
|
|
+ BigDecimal syLb = zqlb.divide(standingyieldbig, 2, RoundingMode.HALF_UP);
|
|
|
|
+ Integer syLbTime = (syLb.multiply(hasStartTimeProcess.get(i).getSinglerollweight()).divide(new BigDecimal(hasStartTimeProcess.get(i).getProduceTime()), 2, RoundingMode.HALF_UP)).intValue()+1;
|
|
|
|
+
|
|
|
|
+ if(serspre.length == 5 && sersafter.length == 5){
|
|
|
|
+ // 合金不同则需要换辊和立板
|
|
|
|
+ if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(maxTime).plusMinutes(syLbTime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
|
|
+ b++;
|
|
|
|
+ conflictRoptions1.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ conflictRoptions2.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ // 合金相同情况下后面的宽度大于前面的宽度需要换辊和立板
|
|
|
|
+ // 合金相同情况下后面的宽度小于前面的宽度需要立板
|
|
|
|
+ // 合金相同情况下后面的宽度等于前面的宽度换辊和立板都不需要
|
|
|
|
+ String s1 = serspre[2];
|
|
|
|
+ String s2 = sersafter[2];
|
|
|
|
+ try{
|
|
|
|
+ BigDecimal i1 = new BigDecimal(s1);
|
|
|
|
+ BigDecimal i2 = new BigDecimal(s2);
|
|
|
|
+ if(i1.compareTo(i2)<0){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(maxTime).plusMinutes(syLbTime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
|
|
+ b++;
|
|
|
|
+ conflictRoptions1.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ conflictRoptions2.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
|
|
+ }
|
|
|
|
+ }else if(i1.compareTo(i2)>0){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(standingtime).plusMinutes(syLbTime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
|
|
+ b++;
|
|
|
|
+ conflictRoptions1.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ conflictRoptions2.put("soft-seriesZzLb","和下道工序没有预留足够的周期立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }catch (Exception e){
|
|
|
|
+ e.printStackTrace();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return b;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 换辊和立板时间约束
|
|
* 换辊和立板时间约束
|
|
* @param processes
|
|
* @param processes
|
|
@@ -427,6 +591,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
pp.setCutfinishmin(equipmentRunTime.getCutfinishmin() == null ? 0 : equipmentRunTime.getCutfinishmin());
|
|
pp.setCutfinishmin(equipmentRunTime.getCutfinishmin() == null ? 0 : equipmentRunTime.getCutfinishmin());
|
|
pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
pp.setConflictRoptions(new HashMap<>());
|
|
pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ pp.setProduceTime(equipmentRunTime.getOnceprocessmin());
|
|
|
|
+ pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
|
|
|
|
+ pp.setLastSerialLbWeight(equipmentRunTime.getLastSerialLbWeight());
|
|
hasStartTimeProcess.add(pp);
|
|
hasStartTimeProcess.add(pp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -440,7 +607,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
pp.setCutfinishmin(equipment.getLastProcessCutfinishmin() == null ? 0 : equipment.getLastProcessCutfinishmin());
|
|
pp.setCutfinishmin(equipment.getLastProcessCutfinishmin() == null ? 0 : equipment.getLastProcessCutfinishmin());
|
|
pp.setEndTime(equipment.getLastProcessEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
|
pp.setEndTime(equipment.getLastProcessEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
|
pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
pp.setApsOverallConfig(hasStartTimeProcess.get(0).getApsOverallConfig());
|
|
|
|
+ pp.setProduceTime(equipment.getOnceprocessmin());
|
|
pp.setConflictRoptions(new HashMap<>());
|
|
pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ pp.setLastSerialLbWeight(equipment.getLastSerialLbWeight());
|
|
hasStartTimeProcess.add(0,pp);
|
|
hasStartTimeProcess.add(0,pp);
|
|
}
|
|
}
|
|
for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
@@ -453,6 +622,8 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
Map<String, String> conflictRoptions2 = nextPro.getConflictRoptions();
|
|
Map<String, String> conflictRoptions2 = nextPro.getConflictRoptions();
|
|
if(hasStartTimeProcess.get(i).getSeriesProduceMark() != null && hasStartTimeProcess.get(i+1).getSeriesProduceMark() != null){
|
|
if(hasStartTimeProcess.get(i).getSeriesProduceMark() != null && hasStartTimeProcess.get(i+1).getSeriesProduceMark() != null){
|
|
if("铸轧".equals(hasStartTimeProcess.get(i).getProcessType())){
|
|
if("铸轧".equals(hasStartTimeProcess.get(i).getProcessType())){
|
|
|
|
+ // 周期立板已连续生产吨数
|
|
|
|
+ BigDecimal zqlb = new BigDecimal("0");
|
|
if(!hasStartTimeProcess.get(i).getSeriesProduceMark().equals(hasStartTimeProcess.get(i+1).getSeriesProduceMark())){
|
|
if(!hasStartTimeProcess.get(i).getSeriesProduceMark().equals(hasStartTimeProcess.get(i+1).getSeriesProduceMark())){
|
|
String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
|
|
String[] serspre = hasStartTimeProcess.get(i).getSeriesProduceMark().split("\\^_\\^");
|
|
String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
|
|
String[] sersafter = hasStartTimeProcess.get(i+1).getSeriesProduceMark().split("\\^_\\^");
|
|
@@ -460,11 +631,24 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
int jgtime = hasStartTimeProcess.get(i).getCutfinishmin() + hasStartTimeProcess.get(i+1).getPrepressworkmin();
|
|
int jgtime = hasStartTimeProcess.get(i).getCutfinishmin() + hasStartTimeProcess.get(i+1).getPrepressworkmin();
|
|
// 立板时长(分钟)
|
|
// 立板时长(分钟)
|
|
int standingtime = hasStartTimeProcess.get(i).getApsOverallConfig().getStandingtime()*60;
|
|
int standingtime = hasStartTimeProcess.get(i).getApsOverallConfig().getStandingtime()*60;
|
|
|
|
+ // 周期立板最大重量
|
|
|
|
+ Integer standingyield = hasStartTimeProcess.get(i).getApsOverallConfig().getStandingyield();
|
|
|
|
+ BigDecimal standingyieldbig = new BigDecimal(standingyield);
|
|
// 取最大值
|
|
// 取最大值
|
|
int maxTime = jgtime;
|
|
int maxTime = jgtime;
|
|
if(standingtime>jgtime){
|
|
if(standingtime>jgtime){
|
|
maxTime = standingtime;
|
|
maxTime = standingtime;
|
|
}
|
|
}
|
|
|
|
+ // 周期立板总重量统计
|
|
|
|
+ if(zqlb.compareTo(new BigDecimal("0")) == 0){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getLastSerialLbWeight() != null){
|
|
|
|
+ zqlb = hasStartTimeProcess.get(i).getLastSerialLbWeight();
|
|
|
|
+ }else{
|
|
|
|
+ zqlb = hasStartTimeProcess.get(i).getSinglerollweight();
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ zqlb = zqlb.add(hasStartTimeProcess.get(i).getSinglerollweight());
|
|
|
|
+ }
|
|
if(serspre.length == 5 && sersafter.length == 5){
|
|
if(serspre.length == 5 && sersafter.length == 5){
|
|
// 合金不同则需要换辊和立板
|
|
// 合金不同则需要换辊和立板
|
|
if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
|
|
if(!serspre[0].equals(sersafter[0]) || !serspre[1].equals(sersafter[1])){
|
|
@@ -472,6 +656,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
b++;
|
|
b++;
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的换辊和立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
}
|
|
}
|
|
}else{
|
|
}else{
|
|
// 合金相同情况下后面的宽度大于前面的宽度需要换辊和立板
|
|
// 合金相同情况下后面的宽度大于前面的宽度需要换辊和立板
|
|
@@ -487,12 +672,24 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
b++;
|
|
b++;
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的换辊和立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的换辊和立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
}
|
|
}
|
|
}else if(i1.compareTo(i2)>0){
|
|
}else if(i1.compareTo(i2)>0){
|
|
if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(standingtime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(standingtime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
b++;
|
|
b++;
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的立板时间");
|
|
conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的立板时间");
|
|
conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ // 是否需要周期立板
|
|
|
|
+ if(zqlb.add(hasStartTimeProcess.get(i+1).getSinglerollweight()).compareTo(standingyieldbig)>0){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getEndTime().plusMinutes(standingtime).compareTo(hasStartTimeProcess.get(i+1).getStartTime())>0){
|
|
|
|
+ b++;
|
|
|
|
+ conflictRoptions1.put("hard-seriesProduceTimeWait","和下道工序没有预留足够的立板时间");
|
|
|
|
+ conflictRoptions2.put("hard-seriesProduceTimeWait","和上道工序没有预留足够的立板时间");
|
|
|
|
+ zqlb = new BigDecimal("0");
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}catch (Exception e){
|
|
}catch (Exception e){
|
|
@@ -545,7 +742,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
private Constraint eqTimeCross(ConstraintFactory constraintFactory) {
|
|
private Constraint eqTimeCross(ConstraintFactory constraintFactory) {
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
.filter(pro->{
|
|
.filter(pro->{
|
|
- return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退");
|
|
|
|
|
|
+ return !pro.getProcessType().equals("成退") && !pro.getProcessType().equals("中退") && !pro.getProcessType().equals("小卷成退");
|
|
})
|
|
})
|
|
.join(ProductionProcesses.class,Joiners.equal(ProductionProcesses::getEquipmentId))
|
|
.join(ProductionProcesses.class,Joiners.equal(ProductionProcesses::getEquipmentId))
|
|
.filter((proc1,proc2)->{
|
|
.filter((proc1,proc2)->{
|
|
@@ -568,6 +765,221 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
.asConstraint("eqTimeCross");
|
|
.asConstraint("eqTimeCross");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 硬约束:小卷成退合并约束
|
|
|
|
+ * @param constraintFactory
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Constraint eqTimeCrossMinTuihuo(ConstraintFactory constraintFactory) {
|
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
|
+ .filter(pro->{
|
|
|
|
+ return pro.getProcessType().equals("小卷成退");
|
|
|
|
+ })
|
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
|
|
+ .filter((equipmentId,processes) -> {
|
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
|
+ for (ProductionProcesses process : processes) {
|
|
|
|
+ if(process.getConflictRoptions().containsKey("hard-eqTimeCrossMinTuihuo")){
|
|
|
|
+ process.getConflictRoptions().remove("hard-eqTimeCrossMinTuihuo");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ /*Integer num = eqTimeCrossMinTuihuoCount(processes,"1");
|
|
|
|
+ if(num>0){
|
|
|
|
+ return true;
|
|
|
|
+ }*/
|
|
|
|
+ return true;
|
|
|
|
+ }else{
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .penalize(HardMediumSoftScore.ONE_HARD,(equipmentId,processes)->{
|
|
|
|
+ Integer num = eqTimeCrossMinTuihuoCount(processes,"2");
|
|
|
|
+ return num*100;
|
|
|
|
+ })
|
|
|
|
+ .asConstraint("eqTimeCrossMinTuihuo");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 退火工序冲突计算
|
|
|
|
+ * @param processes
|
|
|
|
+ * @param type(1:是否存在冲突,2:冲突得分计算)
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Integer eqTimeCrossMinTuihuoCount(List<ProductionProcesses> processes,String type){
|
|
|
|
+ if(processes.size()>3){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
|
|
+ if(processes.size()>1){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
|
|
+ int b = 0;
|
|
|
|
+ Equipment equipment = null;
|
|
|
|
+ if(processes != null && processes.size()>0){
|
|
|
|
+ equipment = processes.get(0).getEquipment();
|
|
|
|
+ }
|
|
|
|
+ // 设备承重
|
|
|
|
+ BigDecimal equipmentBearing = equipment.getEquipmentParameter().getEquipmentBearing();
|
|
|
|
+ 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.setEquipment(equipment);
|
|
|
|
+ pp.setEndTime(equipmentRunTime.getEndRunTime());
|
|
|
|
+ pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipmentRunTime.getProcessType());
|
|
|
|
+ pp.setVolumeMetal(equipmentRunTime.getVolumeMetal());
|
|
|
|
+ pp.setVolumeMetalstate(equipmentRunTime.getVolumeMetalstate());
|
|
|
|
+ pp.setBsProcessesId(Arrays.asList(new String[]{"haspcprocess"}));
|
|
|
|
+ pp.setVolumeWidth(equipmentRunTime.getTotalVolumeWidth());
|
|
|
|
+ pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
|
|
|
|
+ pp.setVolumeThickness(equipmentRunTime.getTotalThickness());
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ 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 (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-eqTimeCrossMinTuihuo","作业加工时间有交叉");
|
|
|
|
+ conflictRoptions2.put("hard-eqTimeCrossMinTuihuo","作业加工时间有交叉");
|
|
|
|
+ }
|
|
|
|
+ b++;
|
|
|
|
+ }else{
|
|
|
|
+ List<ProduceOrder> produceOrder1 = prePro.getProduceOrder();
|
|
|
|
+ List<ProduceOrder> produceOrder2 = nextPro.getProduceOrder();
|
|
|
|
+ if(produceOrder1 != null && produceOrder1.size()>0 && produceOrder2 != null && produceOrder2.size()>0
|
|
|
|
+ && produceOrder1.get(0).getId().equals(produceOrder2.get(0).getId())
|
|
|
|
+ && !prePro.getUniqueBsProcessesId().equals(nextPro.getUniqueBsProcessesId())){
|
|
|
|
+ conflictRoptions1.put("hard-eqTimeCrossMinTuihuo","同一坯料计划不同工序退火不能排一起");
|
|
|
|
+ conflictRoptions2.put("hard-eqTimeCrossMinTuihuo","同一坯料计划不同工序退火不能排一起");
|
|
|
|
+ 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()) > 0){
|
|
|
|
+ if("2".equals(type)){
|
|
|
|
+// System.out.println("1:作业加工时间有交叉");
|
|
|
|
+ conflictRoptions1.put("hard-eqTimeCrossMinTuihuo","作业加工时间有交叉");
|
|
|
|
+ conflictRoptions2.put("hard-eqTimeCrossMinTuihuo","作业加工时间有交叉");
|
|
|
|
+ }
|
|
|
|
+ b++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ List<ApsFurnaceInstallationDo> furnaceInstallations = processes.get(0).getApsOverallConfig().getFurnaceInstallations();
|
|
|
|
+ List<ApsMergeFurnaceDo> mergeFurnaces = processes.get(0).getApsOverallConfig().getMergeFurnaces();
|
|
|
|
+
|
|
|
|
+ if(ppMap.size()>1){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
|
|
+ // 检查合并工序是否超过容量
|
|
|
|
+ for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
|
|
|
|
+ List<ProductionProcesses> v = entry.getValue();
|
|
|
|
+ Set<String> groupnames = new HashSet<>();
|
|
|
|
+ BigDecimal totalWeight = new BigDecimal(0);
|
|
|
|
+
|
|
|
|
+ boolean mergeRule = true;
|
|
|
|
+ for (ProductionProcesses productionProcesses : v) {
|
|
|
|
+ totalWeight = totalWeight.add(productionProcesses.getSinglerollweight());
|
|
|
|
+ // 检查小卷退火在哪个组
|
|
|
|
+ String groupname = null;
|
|
|
|
+ for (ApsFurnaceInstallationDo furnaceInstallation : furnaceInstallations) {
|
|
|
|
+ if(productionProcesses.getVolumeMetal().equals(furnaceInstallation.getAlloy())){
|
|
|
|
+ boolean a = true;
|
|
|
|
+ if(furnaceInstallation.getAlloystatus() != null && !furnaceInstallation.getAlloystatus().contains(productionProcesses.getVolumeMetalstate())){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getStartthickness() != null && furnaceInstallation.getStartthickness().compareTo(productionProcesses.getVolumeThickness())>0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getEndthickness() != null && furnaceInstallation.getEndthickness().compareTo(productionProcesses.getVolumeThickness())<0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getStartwidth() != null && new BigDecimal(furnaceInstallation.getStartwidth()).compareTo(productionProcesses.getVolumeWidth())>0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getEndwidth() != null && new BigDecimal(furnaceInstallation.getEndwidth()).compareTo(productionProcesses.getVolumeWidth())<0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(a){
|
|
|
|
+ groupname = furnaceInstallation.getId();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(groupname == null){
|
|
|
|
+ groupname = "group-self-" + productionProcesses.getVolumeMetal() + productionProcesses.getVolumeMetalstate() + productionProcesses.getProducttype() + productionProcesses.getVolumeWidth() + productionProcesses.getVolumeThickness();
|
|
|
|
+ }
|
|
|
|
+ groupnames.add(groupname);
|
|
|
|
+ }
|
|
|
|
+ if(totalWeight.compareTo(equipmentBearing)>0){
|
|
|
|
+ b++;
|
|
|
|
+ mergeRule = false;
|
|
|
|
+ }
|
|
|
|
+ if(groupnames.size()>1){
|
|
|
|
+ boolean a = false;
|
|
|
|
+ for (ApsMergeFurnaceDo mergeFurnace : mergeFurnaces) {
|
|
|
|
+ boolean ab = true;
|
|
|
|
+ for (String groupname : groupnames) {
|
|
|
|
+ if(!mergeFurnace.getCompatibilitygroup().contains(groupname)){
|
|
|
|
+ ab = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(ab){
|
|
|
|
+ a = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(!a){
|
|
|
|
+ b++;
|
|
|
|
+ mergeRule = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(!mergeRule){
|
|
|
|
+ for (ProductionProcesses productionProcesses : v) {
|
|
|
|
+ productionProcesses.getConflictRoptions().put("hard-eqTimeCrossMinTuihuo","不符合小卷退火合并规则");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return b;
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 硬约束:同一个退火炉设备的不同的工步运行时间约束
|
|
* 硬约束:同一个退火炉设备的不同的工步运行时间约束
|
|
* @param constraintFactory
|
|
* @param constraintFactory
|
|
@@ -609,6 +1021,12 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
* @return
|
|
* @return
|
|
*/
|
|
*/
|
|
private Integer eqTimeCrossTuihuoCount(List<ProductionProcesses> processes,String type){
|
|
private Integer eqTimeCrossTuihuoCount(List<ProductionProcesses> processes,String type){
|
|
|
|
+ if(processes.size()>3){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
|
|
+ if(processes.size()>1){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
int b = 0;
|
|
int b = 0;
|
|
Equipment equipment = null;
|
|
Equipment equipment = null;
|
|
if(processes != null && processes.size()>0){
|
|
if(processes != null && processes.size()>0){
|
|
@@ -698,6 +1116,9 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
// 检查合并工序是否超过容量
|
|
// 检查合并工序是否超过容量
|
|
for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
|
|
for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
|
|
List<ProductionProcesses> v = entry.getValue();
|
|
List<ProductionProcesses> v = entry.getValue();
|
|
|
|
+ if(v.size()>3){
|
|
|
|
+ int a = 1;
|
|
|
|
+ }
|
|
BigDecimal totalWidth = new BigDecimal("0");
|
|
BigDecimal totalWidth = new BigDecimal("0");
|
|
BigDecimal totalWeight = new BigDecimal("0");
|
|
BigDecimal totalWeight = new BigDecimal("0");
|
|
Set<String> metalSet = new HashSet<>();
|
|
Set<String> metalSet = new HashSet<>();
|
|
@@ -1355,6 +1776,121 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
.asConstraint("processNear");
|
|
.asConstraint("processNear");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 排程时间尽量靠前
|
|
|
|
+ * @param constraintFactory
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Constraint processBtNear(ConstraintFactory constraintFactory){
|
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
|
+ .filter((process)->{
|
|
|
|
+ return "冷轧".equals(process.getProcessType()) || "铸轧".equals(process.getProcessType());
|
|
|
|
+ })
|
|
|
|
+ .groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
|
|
+ .filter((equipmentId,processs)->{
|
|
|
|
+ if(processs != null && processs.size()>0){
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ })
|
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(equipmentId,processs) -> {
|
|
|
|
+ int b = 0;
|
|
|
|
+ Equipment equipment = null;
|
|
|
|
+ if(processs != null && processs.size()>0){
|
|
|
|
+ equipment = processs.get(0).getEquipment();
|
|
|
|
+ }
|
|
|
|
+ List<ProductionProcesses> hasStartTimeProcess = processs.stream().filter(v -> v.getStartTime() != null).collect(Collectors.toList());
|
|
|
|
+ // 设备占用时间参与连续生产排程
|
|
|
|
+ if(equipment != null && equipment.getEquipmentRunTimes() != null && equipment.getEquipmentRunTimes().size()>0){
|
|
|
|
+ for (EquipmentRunTime equipmentRunTime : equipment.getEquipmentRunTimes()) {
|
|
|
|
+ if(equipmentRunTime.getOccupyType().equals("process")){
|
|
|
|
+ ProductionProcesses pp = new ProductionProcesses();
|
|
|
|
+ pp.setStartTime(equipmentRunTime.getStartRunTime());
|
|
|
|
+ pp.setEndTime(equipmentRunTime.getEndRunTime());
|
|
|
|
+ pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipmentRunTime.getProcessType());
|
|
|
|
+ pp.setBsProcessesId(Arrays.asList(new String[]{"haspcprocess"}));
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ hasStartTimeProcess.add(pp);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 按照开始时间排序
|
|
|
|
+ Collections.sort(hasStartTimeProcess, Comparator.comparing(ProductionProcesses::getSeriSort));
|
|
|
|
+ // 获取设备已排程好的最后一个作业,计算连续加工
|
|
|
|
+ if(equipment.getLastProcessType() != null && equipment.getLastSeriesProduceMark() != null){
|
|
|
|
+ ProductionProcesses pp = new ProductionProcesses();
|
|
|
|
+ pp.setSeriesProduceMark(equipment.getLastSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipment.getLastProcessType());
|
|
|
|
+ pp.setBsProcessesId(Arrays.asList(new String[]{"lastprocess"}));
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ pp.setEndTime(equipment.getLastProcessEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
|
|
|
|
+ hasStartTimeProcess.add(0,pp);
|
|
|
|
+ }
|
|
|
|
+ for(int i=0;i<hasStartTimeProcess.size()-1;i++){
|
|
|
|
+ if(hasStartTimeProcess.get(i).getId() == null && hasStartTimeProcess.get(i+1).getId() == null){
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if("铸轧".equals(hasStartTimeProcess.get(i).getProcessType())){
|
|
|
|
+ if(hasStartTimeProcess.get(i+1).getStartTime().compareTo(hasStartTimeProcess.get(i).getEndTime().plusHours(10))>0){
|
|
|
|
+ b++;
|
|
|
|
+ }
|
|
|
|
+ } else if ("冷轧".equals(hasStartTimeProcess.get(i).getProcessType())) {
|
|
|
|
+ if(hasStartTimeProcess.get(i+1).getStartTime().compareTo(hasStartTimeProcess.get(i).getEndTime().plusHours(10))>0){
|
|
|
|
+ b++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return b*300;
|
|
|
|
+ })
|
|
|
|
+ .asConstraint("processBtNear");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 排程时间尽量靠前
|
|
|
|
+ * @param constraintFactory
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Constraint processLzNear(ConstraintFactory constraintFactory){
|
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
|
+ .filter((process)->{
|
|
|
|
+ return "冷轧".equals(process.getProcessType()) || "铸轧".equals(process.getProcessType());
|
|
|
|
+ })
|
|
|
|
+ .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 && preProcess.getEquipment() != 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.plusHours(48))>0){
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .penalize(HardMediumSoftScore.ONE_MEDIUM,(process) -> {
|
|
|
|
+ return 300;
|
|
|
|
+ })
|
|
|
|
+ .asConstraint("processLzNear");
|
|
|
|
+ }
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* 退火工序组炉规则
|
|
* 退火工序组炉规则
|
|
* @param constraintFactory
|
|
* @param constraintFactory
|
|
@@ -1363,7 +1899,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
private Constraint mergeTuihuo(ConstraintFactory constraintFactory){
|
|
private Constraint mergeTuihuo(ConstraintFactory constraintFactory){
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
return constraintFactory.forEach(ProductionProcesses.class)
|
|
.filter(pro->{
|
|
.filter(pro->{
|
|
- return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退");
|
|
|
|
|
|
+ return pro.getProcessType().equals("成退") || pro.getProcessType().equals("中退") || pro.getProcessType().equals("小卷成退");
|
|
})
|
|
})
|
|
.groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
.groupBy(ProductionProcesses::getEquipmentId,ConstraintCollectors.toList())
|
|
.filter((equipmentId,processes) -> {
|
|
.filter((equipmentId,processes) -> {
|
|
@@ -1397,7 +1933,7 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return ppMap.size()*100;
|
|
|
|
|
|
+ return ppMap.size()*10000;
|
|
})
|
|
})
|
|
.asConstraint("mergeTuihuo");
|
|
.asConstraint("mergeTuihuo");
|
|
}
|
|
}
|
|
@@ -1438,4 +1974,174 @@ public class ApsConstraintProvider implements ConstraintProvider {
|
|
})
|
|
})
|
|
.asConstraint("sameEquipment");
|
|
.asConstraint("sameEquipment");
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 硬约束:小卷成退合并约束
|
|
|
|
+ * @param constraintFactory
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Constraint eqTimeCrossMinTuihuoSoft(ConstraintFactory constraintFactory) {
|
|
|
|
+ return constraintFactory.forEach(ProductionProcesses.class)
|
|
|
|
+ .filter(pro->{
|
|
|
|
+ return 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_SOFT,(equipmentId,processes)->{
|
|
|
|
+ Integer num = eqTimeCrossMinTuihuoCountSoft(processes,"2");
|
|
|
|
+ return num*100;
|
|
|
|
+ })
|
|
|
|
+ .asConstraint("eqTimeCrossMinTuihuoSoft");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * 退火工序冲突计算
|
|
|
|
+ * @param processes
|
|
|
|
+ * @param type(1:是否存在冲突,2:冲突得分计算)
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ private Integer eqTimeCrossMinTuihuoCountSoft(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.setEquipment(equipment);
|
|
|
|
+ pp.setEndTime(equipmentRunTime.getEndRunTime());
|
|
|
|
+ pp.setSeriesProduceMark(equipmentRunTime.getSeriesProduceMark());
|
|
|
|
+ pp.setProcessType(equipmentRunTime.getProcessType());
|
|
|
|
+ pp.setVolumeMetal(equipmentRunTime.getVolumeMetal());
|
|
|
|
+ pp.setVolumeMetalstate(equipmentRunTime.getVolumeMetalstate());
|
|
|
|
+ pp.setBsProcessesId(Arrays.asList(new String[]{"haspcprocess"}));
|
|
|
|
+ pp.setVolumeWidth(equipmentRunTime.getTotalVolumeWidth());
|
|
|
|
+ pp.setSinglerollweight(equipmentRunTime.getTotalSinglerollweight());
|
|
|
|
+ pp.setVolumeThickness(equipmentRunTime.getTotalThickness());
|
|
|
|
+ pp.setConflictRoptions(new HashMap<>());
|
|
|
|
+ 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 (prePro.getStartTime().compareTo(nextPro.getStartTime()) == 0){
|
|
|
|
+ if(prePro.getTaskType().equals("maintenance") || nextPro.getTaskType().equals("maintenance")){
|
|
|
|
+ b = b+100;
|
|
|
|
+ }else{
|
|
|
|
+ List<ProduceOrder> produceOrder1 = prePro.getProduceOrder();
|
|
|
|
+ List<ProduceOrder> produceOrder2 = nextPro.getProduceOrder();
|
|
|
|
+ if(produceOrder1 != null && produceOrder1.size()>0 && produceOrder2 != null && produceOrder2.size()>0
|
|
|
|
+ && produceOrder1.get(0).getId().equals(produceOrder2.get(0).getId())
|
|
|
|
+ && !prePro.getUniqueBsProcessesId().equals(nextPro.getUniqueBsProcessesId())){
|
|
|
|
+ b = b+100;
|
|
|
|
+ }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()) > 0){
|
|
|
|
+ b = b+100;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ List<ApsFurnaceInstallationDo> furnaceInstallations = processes.get(0).getApsOverallConfig().getFurnaceInstallations();
|
|
|
|
+ List<ApsMergeFurnaceDo> mergeFurnaces = processes.get(0).getApsOverallConfig().getMergeFurnaces();
|
|
|
|
+
|
|
|
|
+ // 检查合并工序是否超过容量
|
|
|
|
+ for (Map.Entry<String,List<ProductionProcesses>> entry: ppMap.entrySet()) {
|
|
|
|
+ List<ProductionProcesses> v = entry.getValue();
|
|
|
|
+ Set<String> groupnames = new HashSet<>();
|
|
|
|
+ for (ProductionProcesses productionProcesses : v) {
|
|
|
|
+ // 检查小卷退火在哪个组
|
|
|
|
+ String groupname = null;
|
|
|
|
+ for (ApsFurnaceInstallationDo furnaceInstallation : furnaceInstallations) {
|
|
|
|
+ if(productionProcesses.getVolumeMetal().equals(furnaceInstallation.getAlloy())){
|
|
|
|
+ boolean a = true;
|
|
|
|
+ if(furnaceInstallation.getAlloystatus() != null && !furnaceInstallation.getAlloystatus().contains(productionProcesses.getVolumeMetalstate())){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getStartthickness() != null && furnaceInstallation.getStartthickness().compareTo(productionProcesses.getVolumeThickness())>0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getEndthickness() != null && furnaceInstallation.getEndthickness().compareTo(productionProcesses.getVolumeThickness())<0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getStartwidth() != null && new BigDecimal(furnaceInstallation.getStartwidth()).compareTo(productionProcesses.getVolumeWidth())>0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(furnaceInstallation.getEndwidth() != null && new BigDecimal(furnaceInstallation.getEndwidth()).compareTo(productionProcesses.getVolumeWidth())<0){
|
|
|
|
+ a = false;
|
|
|
|
+ }
|
|
|
|
+ if(a){
|
|
|
|
+ groupname = furnaceInstallation.getId();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(groupname == null){
|
|
|
|
+ groupname = "group-self";
|
|
|
|
+ }
|
|
|
|
+ groupnames.add(groupname);
|
|
|
|
+ }
|
|
|
|
+ if(groupnames.size()>1){
|
|
|
|
+ b = b+10;
|
|
|
|
+ boolean a = false;
|
|
|
|
+ for (ApsMergeFurnaceDo mergeFurnace : mergeFurnaces) {
|
|
|
|
+ boolean ab = true;
|
|
|
|
+ for (String groupname : groupnames) {
|
|
|
|
+ if(!mergeFurnace.getCompatibilitygroup().contains(groupname)){
|
|
|
|
+ ab = false;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(ab){
|
|
|
|
+ a = true;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if(!a){
|
|
|
|
+ b = b+100;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return b;
|
|
|
|
+ }
|
|
}
|
|
}
|